C++ unordered_map 实现原理

C++ 常用的map类容器就是 map 和 unordered_map

map的实现原理就是红黑树 每个节点到叶子节点最大树高不超过1 是平衡二叉树。查找的时间复杂度是O(lgn),但是插入和删除要维持红黑树的自平衡,所以效率较低。但是有序。

unordered_map是c++11正式加入的对hashmap的官方实现(之前标准c++没有对hashmap的官方实现,我们用的都是非官方的实现,例如平台自己的实现,hash_map中也建议以后都使用unordered_map不要使用hashmap),从名字可以看出这个结构是无序的,底层使用hashtable+buket的实现原理,hashtable可以看作是一个数组 或者vector之类的连续内存存储结构(可以通过下标来快速定位时间复杂度为O(1))处理hash冲突的方法就是在相同hash值的元素位置下面挂buket(桶),当数据量在8以内使用链表来实现桶,当数据量大于8 则自动转换为红黑树结构 也就是有序map的实现结构。

所以查询一个树最差的时间复杂度是:首先进行一次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。

另外unordered_map底层设计使用的是hashtable。hashtable槽数是根据需要分配的,但是一般都是2的n次方大小(unordered_map底层实现既是如此)。这种设计在计算桶号的时候有一个优势就是可以使用按位与(&)来加快计算。

int Index = hash & (length-1)

原理是在计算除法的时候如果被除数是2的n次方,其实就是把除数的二进制右移n位后被移掉的二进制对应的数值。

具体来说一下:

例如 9 % 8

这里8 = 2的3次方,所以相当与把9的二进制(1001)右移3位,移掉的是001,那么余数(移掉的就是多余的数)就是1。

这里就是 9 & (8-1) 之所以是length-1这里是8-1是因为对2的n次方的二进制正好是1后面n个0。例如8的二进制是1后面3个0,1000。减1后正好是0111,后面的三个1按位与运算后正好完整的保留了除数被移掉的部分所以按位与的结果就是取余的结果。

所以这里可以加快运算,也算是一个小技巧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值