c++ set与unordered set的区别
c++ std中set与unordered_set区别和map与unordered_map区别类似,其底层的数据结构说明如下:
1、set基于红黑树实现,红黑树具有自动排序的功能,因此map内部所有的数据,在任何时候,都是有序的。
2、unordered_set基于哈希表,数据插入和查找的时间复杂度很低,几乎是常数时间,而代价是消耗比较多的内存,无自动排序功能。底层实现上,使用一个下标范围比较大的数组来存储元素,形成很多的桶,利用hash函数对key进行映射到不同区域进行保存。
更详细的区别,如下图:

set与unordered相比:
1、set比unordered_set使用更少的内存来存储相同数量的元素。
2、对于少量的元素,在set中查找可能比在unordered_set中查找更快。
3、尽管许多操作在unordered_set的平均情况下更快,但通常需要保证set在最坏情况下有更好的复杂度(例如insert)。
4、如果您想按顺序访问元素,那么set对元素进行排序的功能是很有用的。
5、您可以用<、<=、>和>=从字典顺序上比较不同的set集。unordered_set集则不支持这些操作。
一般来说,在如下情况,适合使用set:
1、我们需要有序的数据(不同元素)。
2、我们必须打印/访问数据(按排序顺序)。
3、我们需要知道元素的前任/继承者。
一般来说,在如下情况,适合使用unordered_set:
1、我们需要保留一组元素,不需要排序。
2、我们需要单元素访问,即不需要遍历。
3、仅仅只是插入、删除、查找的话。
示例:
set:
Input : 1, 8, 2, 5, 3, 9
Output : 1, 2, 3, 5, 8, 9
unordered_set:
Input : 1, 8, 2, 5, 3, 9
Output : 9 3 1 8 2 5 (顺序依赖于 hash function)
下面再给出一个以vector<int>为key的示例,对比下set与unordered_set:
1 set<vector<int>> s;
2 s.insert({1, 2});
3 s.insert({1, 3});
4 s.insert({1, 2});
5
6 for(const auto& vec:s)
7 cout<<vec<<endl;
8 // 1 2
9 // 1 3
因为vector重载了operator<,因此可以作为set的key。
但是如果直接使用unordered_set<vector<int>> s;则报错,因为vector没有hash函数,需要自己定义一个,可以定义一个类似下面这样的hash函数:
1 struct VectorHash {
2 size_t operator()(const std::vector<int>& v) const {
3 std::hash<int> hasher;
4 size_t seed = 0;
5 for (int i : v) {
6 seed ^= hasher(i) + 0x9e3779b9 + (seed<<6) + (seed>>2);
7 }
8 return seed;
9 }
10 };
接下来这样使用:
1 unordered_set<vector<int>, VectorHash> s;
2 s.insert({1, 2});
3 s.insert({1, 3});
4 s.insert({1, 2});
5
6 for(const auto& vec:s)
7 cout<<vec<<endl;
8 // 1 2
9 // 1 3
或者模板特化struct hash<std::vector<int>>
1 namespace std {
2 template<>
3 struct hash<std::vector<int>> {
4 size_t operator()(const vector<int> &v) const {
5 std::hash<int> hasher;
6 size_t seed = 0;
7 for (int i : v) {
8 seed ^= hasher(i) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
9 }
10 return seed;
11 }
12 };
13 }
14
15 // usage example
16 void test_unordered_set(){
17 unordered_set<std::vector<int>> s;
18 s.insert({1, 2});
19 s.insert({1, 3});
20 s.insert({1, 2});
21 for(const auto& vec:s)
22 cout<<vec<<endl;
23 // 1 3
24 // 1 2
25
26 std::hash<int> hasher;
27 cout<<"hasher(99): "<<hasher(99)<<" ,hasher(77): "<<hasher(77)<<endl;
28 // hasher(99): 99 ,hasher(77): 77
29 }
可以看到,在某些情况下,unordered_set的使用门槛还是挺高的。
Input : 1, 8, 2, 5, 3, 9
Output : 1, 2, 3, 5, 8, 9
c++ set与unordered set的区别的更多相关文章
- 2.8 C++STL set/multiset容器详解
文章目录 2.8.1 引入 2.8.2 代码示例 2.8.3 代码运行结果 2.8.4 对组pair的补充 代码实例 运行结果 总结 2.8.1 引入 set/multiset容器概念 set和mul ...
- mootools里选择器$,$$,$E,$ES等的区别
区别就是 $和$$都是1个参数, $适用于ID,或者ID代表的对象 $$适用于CSS选择器 $E和$ES,有2个参数,第二个参数是可选参数代表(filter,即某个ID范围里的元素) $E('inpu ...
- html中ul,ol和li的区别
ul是无序列表,全称是unordered list,先来个例子: ●张三 ●李四 ●王二 ●刘五 ol是有序列表 ,全称是ordered list,同样举个例子: 1.张 ...
- c#与java的区别
经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...
- jquery和Js的区别和基础操作
jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...
- 【原】nodejs全局安装和本地安装的区别
来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...
- 探究@property申明对象属性时copy与strong的区别
一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...
- X86和X86_64和X64有什么区别?
x86是指intel的开发的一种32位指令集,从386开始时代开始的,一直沿用至今,是一种cisc指令集,所有intel早期的cpu,amd早期的cpu都支持这种指令集,ntel官方文档里面称为&qu ...
- Java中Comparable与Comparator的区别
相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...
随机推荐
- linux 设置connect 超时代码[select/epoll]
转载请注明来源:https://www.cnblogs.com/hookjc/ linux下socket编程有常见的几个系统调用: 对于服务器来说, 有socket(), bind(),listen( ...
- LVS负载均衡群集部署——NAT模式
LVS负载均衡群集部署--NAT模式 1.群集应用概述 2.NAT模式LVS负载均衡群集部署 1.群集应用概述: 存在的问题: 互联网应用中,随着站点对硬件性能.响应速度.服务稳定性.数据可靠性等要求 ...
- abp vnext 调试
在用Abp或者asp.net core 开发过程中,难免会遇到稀奇古怪的问题,需要对底层源代码进行调试,下面就教大家如何通过配置Visual Studio 2019来进行调试: 首先我们通过查看Abp ...
- VLAN介绍及实验
目录 一.VLAN 1.1.VLAN的概念及优势 1.2.VLAN的种类 1.3.静态VLAN的配置 1.4.Trunk的作用 1.5.配置实验 1.搭建拓扑图 2.交换机SW1配置情况 3.交换机S ...
- Solution -「OurOJ 46544」漏斗计算
\(\mathcal{Description}\) Link. 定义一个运算结点 \(u\) 有两个属性:当前容量 \(x_u\).最大容量 \(V_u\).提供以下单元操作: I 读入一个整 ...
- Filter(过滤器)与Listener(监听器)详解
11.Filter(重点) Filter:过滤器,用来过滤网站的数据: 处理中文乱码 登陆验证... Filter开发步骤: 导包 编写过滤器 导包不要错 实现Filter接口,重写对应的方法即可 p ...
- c++ struct enum union加typedef与不加typedef
struct/enum/union加typedef与不加typedef 匿名结构体 struct { int a; int b; } v; // 这里表示定义了一个结构体的变量v,且结构体类型没有名字 ...
- Python基础—函数(Day9)
一.函数的定义 def 关键字,定义一个函数 my_len 函数名(书写规则与变量名一样) def与函数名中间一个空格. def与函数名中间一个空格. 函数名():加冒号 函数体 my_len()#函 ...
- Dubbo基础三之配置方式简述
Dubbo基础一之实战初体验 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中,体验了两种配置方式一种注解一种xml.其中xml是在注解配置失败没有找到解决方法后选择xml替代体验的.那 ...
- LibOpenCM3(二) 项目模板 Makefile分析
目录 LibOpenCM3(一) Linux下命令行开发环境配置 LibOpenCM3(二) 项目模板 Makefile分析 LibOpenCM3 项目模板 项目模板地址: https://githu ...