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的区别的更多相关文章

  1. 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 ...

  2. mootools里选择器$,$$,$E,$ES等的区别

    区别就是 $和$$都是1个参数, $适用于ID,或者ID代表的对象 $$适用于CSS选择器 $E和$ES,有2个参数,第二个参数是可选参数代表(filter,即某个ID范围里的元素) $E('inpu ...

  3. html中ul,ol和li的区别

    ul是无序列表,全称是unordered list,先来个例子:    ●张三    ●李四    ●王二    ●刘五   ol是有序列表 ,全称是ordered list,同样举个例子:  1.张 ...

  4. c#与java的区别

    经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...

  5. jquery和Js的区别和基础操作

    jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...

  6. 【原】nodejs全局安装和本地安装的区别

    来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...

  7. 探究@property申明对象属性时copy与strong的区别

    一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...

  8. X86和X86_64和X64有什么区别?

    x86是指intel的开发的一种32位指令集,从386开始时代开始的,一直沿用至今,是一种cisc指令集,所有intel早期的cpu,amd早期的cpu都支持这种指令集,ntel官方文档里面称为&qu ...

  9. Java中Comparable与Comparator的区别

    相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...

随机推荐

  1. linux 设置connect 超时

    转载请注明来源:https://www.cnblogs.com/hookjc/ 将一个socket 设置成阻塞模式和非阻塞模式,使用fcntl方法,即: 设置成非阻塞模式: 先用fcntl的F_GET ...

  2. indexOf() 和 lastIndexOf()

    一,定义和用法 indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置. lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索 ...

  3. go基础——基本数据类型

    GO语言的数据类型: /* GO语言的数据类型: 1.基本数据类型: 布尔类型:true,false 数值类型:整数,浮点,复数complex 字符串:string 2.复合数据类型 array,sl ...

  4. python篇第5天【变量】

    第4天加班 多个变量赋值 Python允许你同时为多个变量赋值.例如: a = b = c = 1 以上实例,创建一个整型对象,值为1,三个变量被分配到相同的内存空间上. 您也可以为多个对象指定多个变 ...

  5. 帆软报表(finereport)单元格函数,OP参数

    单元格模型:单元格数据和引用:数据类型.实际值与显示值.单元格支持的操作单元格样式:行高列宽.隐藏行列.自动换行.上下标.文字竖排.大文本字段分页时断开.标识说明.格式刷单元格Web属性:web显示. ...

  6. 我是如何破解你的WINDOWS密码的 ?(2)

    介绍 在这个系类的第一部分中,我们揭示了windows创建和储存密码的机制.我们也涉猎了一点两种加密方法的弱点和破解的方法.在这系列的第二篇也是最后一篇文章中,我会实战用网上免费的工具一步一步的来破解 ...

  7. suse 12安装 python-pip

    文章目录 方法一 安装setup-tools 安装pip 方法二 配置阿里云pip源 pip安装pyotp 方法一 安装setup-tools linux-oz6w:~ # wget https:// ...

  8. EXCEL应用之商机分析:企业商机分析模板免费用

    ​一.分析背景 商机是订单的来源,因此抓住每个销售机会,就可以更多地赢得交易.商机管理可以说是业务环节中最为关键的一步.每个企业都有自己的商机阶段划分,从销售人员接触客户.发现商机.跟进商机.推进销售 ...

  9. C#值类型回收

    函数调用在执行时,首先要在栈中为形参和局部变量分配存储空间,然后还要将实参的值复制给形参,接下来还要将函数的返回地址(该地址指明了函数执行结束后,程序应该回到哪里继续执行)放入栈中,最后才跳转到函数内 ...

  10. 【C# 】继承

    背景..什么是继承? 「继承」是对象导向编程的其中一个基本属性. 它可让您定义子类,重复使用(继承).扩充或修改父类别行为. 其成员可供继承的类别称为基底类别. 继承基底类别成员的类别则称为「衍生类别 ...