C++ unordered_map原理

27 篇文章 2 订阅

 

 

C++11推出了4个新的关联式容器:unordered_map,unordered_set, unordered_multimap, unordered_multiset, 即加入了unordered系列的容器。

这4个关联式容器与map,multimap,set,multiset功能基本类似,最主要就是底层结构不同,使用场景不容。

如果需要得到一个有序序列,使用红黑树系列的关联式容器,如果需要更高的查询效率,使用以哈希表为底层的关联式容器。 

 

unordered_map是c++11正式加入的对hashmap的官方实现。


unordered_map 原理

hashtable + bucket:

 unordered_map 内部采用 hashtable 的数据结构存储,每个特定的 key 会通过特定的哈希运算映射到一个特定的位置。

一般来说,hashtable 是可能存在冲突的,即不同的key值经过哈希运算之后得到相同的结果。解决方法是:在每个位置放一个桶,用于存放映射到此位置的元素,  当桶内数据量在8以内使用链表来实现桶,当数据量大于8 则自动转换为红黑树结构 也就是有序map的实现结构。


插入过程是:
1、得到 key;
2、通过 hash 函数得到 hash 值;
3、得到桶号(一般都为 hash 值对桶数求模);
4、存放 key 和 value 在桶内;

取值过程是:
1、得到 key
2、通过 hash 函数得到 hash 值
3、得到桶号(一般都为 hash 值对桶数求模)
4、比较桶的内部元素是否与 key 相等,若都不相等,则没有找到。
5、取出相等的记录的 value。

 

定位时间复杂度为O(1),同 数组 或者vector之类的连续内存存储结构。

 

查询一个key最差的时间复杂度是:

首先进行一次hash运算找到桶的位置,然后使用链表或者红黑树来继续查找(所有元素在同一个桶里,其他桶位全为空,这个桶位其实就是一个数组下面挂红黑树也就是挂了一个map的结构),所以时间复杂度是计算hash+O(1)+O(lgn)。

但是这几乎是不可能的。在一个设计正常的hash函数里结果应该是偏向平均的,至少设计方向是偏向平均的。这样时间复杂度就是计算hash+O(1)+O(lg(n/m)), m是桶数(通常设计为2的n次方)。根据时间复杂度的取值规则时间复杂度为O(lgn/m)。

无论是查找效率还是插入、删除效率unordered_map都优于map。所以在对数据不要求有序的情况下,尽量使unordered_map。除非你对数据要求有序才去使用map.


一个桶内的数据量在8以内使用链表来实现桶,当数据量大于8 后转换为红黑树结构的原因:

嗯,根本原因还是红黑树的查找时间复杂度为log n,而链表为n吧;至于为何选择8,查到论坛上有两种说法:

1) 黑树的查找时间的平均复杂度为log n,而链表为n/2,8是一个分割点;

2)泊松分布的角度,,我没有理解。

https://blog.csdn.net/it_qingfengzhuimeng/article/details/99735683

https://www.cnblogs.com/linghu-java/p/10598758.html


Ref:

https://www.jianshu.com/p/56bb01df8ac7

https://www.cnblogs.com/tp-16b/p/9156810.html

https://blog.csdn.net/baihebeijixing/article/details/104349309/

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

First Snowflakes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值