【C++/STL关联式容器】

系列文章数据结构


map和set的各种实现中的名称对应如表,低层实现几乎相同。

stl boost java
map/multimap、set/mutiset map/multimap、set/mutiset treemap/treemultimap、treeset/treemultiset
unordered_map/unordered_multimap、unordered_set/unordered_multiset hash_map/hash_multimap、hash_set/hash_multiset hashmap/hashmultimap、hashset/hashmultiset

map/multimap、set/mutiset【红黑树】

底层是红黑树实现,红黑树4大规则:

1.节点是红或黑
2.根结点和叶节点为黑
3.红节点有两个黑的子节点
4.从根结点开始的每条路径的黑色节点数相同

规则3和规则4保证了任意节点到其每个叶子节点路径最长不会超过最短路径的2倍,因为最长路径和最短路径的黑色节点数相同,极端情况下最短路径就是全有黑色节点组成,而红色节点不能连续出现,因此最多就交替出现,则极端情况下最长路径红色节点 = 黑色节点,所以最长路径不会超过最短路径两倍。
红黑树的操作包括旋转、插入、删除等,网上很多资料可以查看,此处不再赘述。。


unordered_map/unordered_multimap、unordered_set/unordered_multiset【哈希表】

扩容策略:c++/stl的实现和java的实现不太一样

c++/stl java
桶元素超过8个或者装载因子超过0.75则扩容 桶元素超过8个则将桶指向的列表元素由链表转变为红黑树,当装载因子超过0.75则扩容

注意:c++实现的unordered_map没有转红黑树这个操作,要是桶大小超过8个元素,就直接扩容重哈希。

装载因子定0.75、桶大小定8原因?
首先定装载因子和桶大小是为了扩容和将链表转为红黑树。
扩容和链表转为红黑树是时间和空间成本的tradeoff,因为hash表的特性,随着数据增多,产生碰撞概率加大,则开链的长度越长。那么在每个桶的链条中找数据耗费时间就多了,因此扩容重哈希一下。

哈 希 表 可 存 放 数 据 大 小 = 哈 希 表 长 度 ∗ 装 载 因 子 哈希表可存放数据大小 = 哈希表长度 * 装载因子 =
从公式可以看出,要想要哈希表可以存放更多的数据,可以从两个方面进行改进:
1. 牺牲空间换时间:增加哈希表长度(扩容),扩容后碰撞概率变小,桶的链大小变短,找到元素速度变快,但是牺牲了扩容的空间大小。
2. 牺牲时间换空间:增加装载因子大小(装载因子大小介于0~1之间),最大可以设为1,但是装载因子越大,碰撞概率越高,桶的链大小越长,找到元素速度变慢,但是不需要扩容哈希表的大小。
因此为了权衡时间和空间效率,需要设定一个合适的装载因子,通过计算装载因子在0.6~0.8之间,每个桶的链长度不会过长,桶的链长度为8时的概率是亿分之六了,所以业界就协商一个0.6-0.8之间的一个数,最好肯定是定0.8呀,毕竟装载因子越大,不许扩容条件下可以塞更多元素,但是最后还是源码编写大神们将装载因子定为了0.75(挺不错的数,为什么呢,因此哈希表的长度(初识长度为16按2倍扩容)一般是2的幂次方,2的幂次方乘0.75是个整数呀,乘于0.8可不一定是整数)。
为什么哈希表的容量要取2的幂呢?
采用二进制位操作 & 相对于 % 能够提高运算效率,取模运算中如果除数是2的幂次方则等价于其与除数减一的&操作,即:
 hash  %  length  = =  hash  & (  length  − 1 ) \text { hash } \% \text { length }==\text { hash } \&(\text { length }-1)  hash % length == hash 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值