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/