C++ STL中 set 和 map 的区别

embedded/2024/10/9 7:19:04/

目录

1.引言

2.set

3.map

4.共同点

5.不同点

6.高级用法与注意事项

7.总结


1.引言

        在C++的标准模板库(STL)中,setmap是两种常用的容器,它们提供了不同的功能和使用场景。尽管它们底层都基于红黑树实现,有许多相似之处,但在具体用途和接口上却有明显的区别。本文将详细探讨setmap的差异,帮助大家在实际编程中更好地选择和使用它们。

2.set

set是一种关联容器,主要用于存储唯一的、已排序的元素。在set中,每个元素都是唯一的,且set会自动根据元素的值进行排序(默认按升序)。试图插入重复元素将被忽略,这是set设计的初衷。确保插入前元素的唯一性,或利用此特性进行去重或排序。set内部实现通常采用红黑树,因此其插入、删除和查找操作的时间复杂度为O(log n)。

#include <set>
#include <iostream>int main() {std::set<int> mySet = {3, 1, 4, 1, 5, 9};  // 自动排序并去重for (int num : mySet) {std::cout << num << " ";}mySet.insert(10); // 成功插入mySet.insert(10); // 重复,不会插入return 0;
}

3.map

map也是一种关联容器,但它存储的是键值对(key-value pairs)。在map中,每个键都是唯一的,且map会根据键的值自动排序(默认按升序)。值可以重复。键用于排序和查找,值则存储实际数据。尝试插入已存在的键会导致插入失败,而不是覆盖原有值。若需覆盖,请先检查键是否存在,再决定插入或更新。set类似,map的内部实现也基于红黑树,因此其插入、删除和查找操作的时间复杂度同样为O(log n)。

#include <iostream>
#include <map>
using namespace std;#include <string>void TestMap()
{map<string, string> m;// 向map中插入元素的方式:// 将键值对<"peach","桃子">插入map中,用pair直接来构造键值对m.insert(pair<string, string>("peach", "桃子"));// 将键值对<"peach","桃子">插入map中,用make_pair函数来构造键值对m.insert(make_pair("banan", "香蕉"));// 借用operator[]向map中插入元素/*operator[]的原理是:用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器operator[]函数最后将insert返回值键值对中的value返回*/// 将<"apple", "">插入map中,插入成功,返回value的引用,将“苹果”赋值给该引用结果,m["apple"] = "苹果";// key不存在时抛异常//m.at("waterme") = "水蜜桃";cout << m.size() << endl;// 用迭代器去遍历map中的元素,可以得到一个按照key排序的序列for (auto& e : m)cout << e.first << "--->" << e.second << endl; // 遍历键值对cout << endl;// map中的键值对key一定是唯一的,如果key存在将插入失败auto ret = m.insert(make_pair("peach", "桃色"));if (ret.second)cout << "<peach, 桃色>不在map中, 已经插入" << endl;elsecout << "键值为peach的元素已经存在:" << ret.first->first << "--->" <<ret.first->second << " 插入失败" << endl;// 删除key为"apple"的元素m.erase("apple");if (1 == m.count("apple"))cout << "apple还在" << endl;elsecout << "apple被吃了" << endl;
}int main()
{TestMap();return 0;
}

4.共同点

  1. 有序性set 和 map 都是有序的容器,它们的元素会根据一定的排序准则(通常是 < 运算符,但也可以是自定义的比较函数或函数对象)自动排序。
  2. 唯一性set 和 map 中的元素都是唯一的,不允许有重复的元素。
  3. 自动平衡:它们的底层实现通常基于红黑树(Red-Black Tree),因此插入、删除和查找操作的时间复杂度都是 O(log n)。

5.不同点

  1. 存储的元素类型
    • set 存储的是单个元素,每个元素都是唯一的。
    • map 存储的是键值对(key-value pairs),其中键(key)是唯一的,但值(value)可以重复。
  2. 元素访问方式
    • set 中的元素只能通过迭代器访问,或者通过 find 方法查找。
    • map 中的元素可以通过键(key)直接访问,例如 map[key],或者通过 find 方法查找。
  3. 迭代器类型
    • set 的迭代器指向的是单个元素。
    • map 的迭代器指向的是键值对(pair<const Key, T>)。
  4. 适用场景
    • set 适用于需要存储唯一元素并且需要排序的场景,比如去重和排序后的集合。
    • map 适用于需要存储键值对并且需要根据键进行快速查找、插入和删除的场景,比如字典或缓存。
  5. 额外功能

     1.set:提供如lower_boundupper_bound等成员函数,方便进行范围查找;

                            支持一些集合运算,如并集、交集、差集等(通过STL算法库实现)。    

     2.mapmap的键可以是任意类型,只要支持<操作符(或提供自定义比较函数)。

                            map的值可以是任意类型,甚至是另一个mapset

     6.性能对比

        在大多数情况下,setmap的性能是相近的,因为它们的底层实现都是红黑树。然而,由于map需要额外存储键和值,因此在内存占用上可能会比set更高一些。

6.高级用法与注意事项

1. 自定义排序

我们可以通过提供自定义的比较函数或函数对象来改变setmap的默认排序行为。

set:

#include <set>
#include <iostream>
#include <functional>struct MyStruct {int id;std::string name;
};// 自定义比较函数
bool compareMyStruct(const MyStruct& a, const MyStruct& b) {return a.id < b.id;
}int main() {std::set<MyStruct, std::function<bool(const MyStruct&, const MyStruct&)>> mySet(compareMyStruct);mySet.insert({1, "Alice"});mySet.insert({2, "Bob"});mySet.insert({3, "Charlie"});for (const auto& item : mySet) {std::cout << item.id << ": " << item.name << std::endl;}return 0;
}

map:

#include <map>
#include <iostream>
#include <string>
#include <functional>// 自定义比较函数
struct CustomCompare {bool operator()(const std::string& a, const std::string& b) const {return a > b;  // 降序排序}
};int main() {std::map<std::string, int, CustomCompare> myMap;myMap["apple"] = 1;myMap["banana"] = 2;myMap["cherry"] = 3;for (const auto& pair : myMap) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;
}

2.多线程安全

setmap都不是线程安全的,如果在多线程环境中使用,需要手动进行同步。

3.迭代器失效

setmap中,插入不会使迭代器失效,但删除操作会使指向删除元素的迭代器失效。因此,在进行删除操作时,需要特别注意迭代器的有效性。

7.总结

setmap是C++ STL中两种重要的关联容器,它们各自有不同的特点和适用场景。set主要用于存储唯一且排序的元素,而map则用于存储键值对,并根据键进行排序。尽管它们在底层实现上有许多相似之处,但在接口和使用上却有明显的区别。通过理解这些区别,我们可以更好地选择和使用它们,以满足不同的编程需求。


http://www.ppmy.cn/embedded/124939.html

相关文章

Collection 和 Collections 有什么区别?

Collection 和 Collections 在 Java 中是两个截然不同的概念&#xff0c;它们之间的主要区别体现在定义、性质、功能和使用上。 一、定义与性质 Collection 定义&#xff1a;Collection 是 Java 集合框架中的一个根接口&#xff0c;表示一组对象的集合。性质&#xff1a;它是一…

Java入门(基础,常见API,JVM,JUC并发编程)

一.javaSE Java初学者软件安装与idea快捷键-CSDN博客 Java基本概念&#xff08;新手入门&#xff09;_阿伟java资料-CSDN博客 二.常见API JavaAPI-CSDN博客 三.JVM JVM入门-CSDN博客 四.JUC并发编程 JUC并发编程-CSDN博客

【SQL】掌握SQL查询技巧:数据筛选与限制

目录 1. DISTINCT&#xff1a;避免重复记录1.1 示意图1.2 使用场景 2. LIMIT&#xff1a;控制查询结果的数量2.1 示意图2.2 使用场景 3. OFFSET&#xff1a;跳过前几行3.1 示意图3.2 使用场景 4. WHERE子句&#xff1a;精细控制数据过滤4.1 示意图4.2 运算符详细说明4.3 基本条…

边缘端大模型是怎么部署的?重点关注哪些?

写在前面 在设备端运行的大语言模型&#xff08;LLMs&#xff09;&#xff0c;即指在边缘设备上运行LLMs&#xff0c;因其出色的隐私保护、低延迟和节省带宽的特点而引起了广泛关注。然而&#xff0c;与功能更为强大的云中心相比&#xff0c;设备端LLMs的能力本质上受到边缘设…

旅游避坑指南

1.火车站旁白的小摊贩&#xff0c;还有周边的小饭店百分之百是黑店&#xff0c;不仅难吃要死而且巨黑&#xff01;&#xff01;&#xff01; 可以地图上搜索附近的大型商超&#xff0c;例如泰安市的银座商超&#xff0c;里面的东西不仅好吃而且价格透明&#xff0c;还有很多当…

Qt 6 相比 Qt 5 的主要提升与更新

自从 Qt 6 发布以来&#xff0c;作为 Qt 框架的一个重大版本更新&#xff0c;它在多个核心方面进行了深度优化和改进。与 Qt 5 相比&#xff0c;Qt 6 不仅提升了性能&#xff0c;还改进了对现代硬件和图形 API 的支持&#xff0c;并增强了开发者的工作流程。本文将详细介绍 Qt …

ubuntu24开启启动脚本

因为我是在之前装的是windows和ubuntu双系统,所以想在ubuntu中自动挂载和开启时做些自己的脚本处理开发环境。 我的脚本如下: truedei@truedei-code:~$ cat mount.shsudo umount /media/truedei/*#sudo ntfsfix /dev/sda3 #sudo ntfsfix /dev/sda4 #sudo ntfsfix /dev/sda5…

Unity实战案例全解析:RTS游戏的框选和阵型功能(5)阵型功能 优化

前篇&#xff1a;Unity实战案例全解析&#xff1a;RTS游戏的框选和阵型功能&#xff08;4&#xff09;阵型功能-CSDN博客 本案例来源于unity唐老狮&#xff0c;有兴趣的小伙伴可以去泰克在线观看该课程 我只是对重要功能进行分析和做出笔记分享&#xff0c;并未无师自通&#x…