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都 ...
随机推荐
- SqlServer数据库表生成C# Model实体类SQL语句——补充
在sql语句最前边加上 use[数据库名] 原链接:https://www.cnblogs.com/jhli/p/11552105.html --[SQL骚操作]SqlServer数据库表生成C ...
- nodejs并行无关联
var async = require('async'); //串行无关联series//串行有关联waterfall//并行:parallel //会把各个函数的执行结果一起放到最后的回调中asyn ...
- Windows office2019免费激活,附代码
office2019地址:链接:https://pan.baidu.com/s/1zPt5U7b0L-bGHl5AOtYs2w提取码:m5ei 新建一个txt,然后把这段代码放进去,然后保存关闭改后缀 ...
- Solution -「CEOI 2006」「洛谷 P5974」ANTENNA
\(\mathcal{Description}\) Link. 给定平面上 \(n\) 个点,求最小的能覆盖其中至少 \(m\) 个点的圆半径及一个可能的圆心. \(n\le500\),坐 ...
- Solution -「LOCAL」模板
\(\mathcal{Description}\) OurOJ. 给定一棵 \(n\) 个结点树,\(1\) 为根,每个 \(u\) 结点有容量 \(k_u\).\(m\) 次操作,每次操作 ...
- mysql悬案 之 为什么用docker启动的mysql配置文件不生效
文章目录 故事前景 查看docker启动时挂载了哪些目录 使用相同镜像启动一个mysql 新建一个目录用来存放容器内的mysql配置文件 复制容器内的mysql配置文件到本地 查看mysql配置文件目 ...
- linux 运维工程师如何降低工作难度
文章目录 1.Linux "优化" 2.git "优化" 3.mysql "优化" 4.kubernetes "优化" ...
- Dubbo扩展点应用之二负载均衡
负载均衡其本质就是将请求分摊到多个操作单元上进行,从而共同完成工作任务.其策略主要用于客户端春常在多个提供者时根据算法选择某个提供者.在集群负载均衡时,Dubbo提供了多种均衡策略(包括随机.轮询.最 ...
- vue实例中的watch属性
watch 就是监听,当数据发生改变的时候就执行 data:{ num1:1, num2:2 }, watch:{ num1(newValue){ }, num2(newValue,oldValue) ...
- python-利用json模块处理json数据几个函数总结
1.前言 json是一种轻量级的数据交换格式,它是JavaScript的子集,易于人阅读和编写. 前端和后端进行数据交互,其实就是JS和Python进行数据交互. 接口间或者前后端间的语言不一致,不同 ...