【STL】rb_tree (multi)set (multi)map

rb_tree

rb_tree源码实现

G2.9版本的rb_tree源码

rb_tree底层实现红黑树,其示意图和代码如下:
在这里插入图片描述

  • 4个需要注意的模板参数:Key,Value,KeyOfValue,Compare
    Key就是Key,节点的大小关系是按Key排的;Value是整个node,而不是key对应的data,比如对于map来说,Value就是个pair;KeyOfValue代表如何从Value中提取出Key,也就是一个可调用对象的类型,传入一个Value,返回对应的Key;Compare提供两个Key比较的依据
  • 留意rb_tree成员header,类型是一个指向rb_tree_node的指针,rb_tree_node表示红黑树的节点类型,里面包含一个value对象,以及指向parent,left和right的指针。
  • rb_tree可以实现遍历和iterator操作,即rb_tree通过中序遍历所有元素
  • rb_tree节点的key值不可以改变,因为随意改变会破坏红黑树的结构
  • rb_tree主要提供insert_unique()和insert_equal()操作,前者表示key在rb_tree中独一无二,否则安插失败,后者表示key在rb_tree可以重复存在
  • rb_tree初始长度为12字节,因为rb_tree的成员node_count,header分别为4字节,key_compare为一个没有元素的函数,大小应为0,但是实际上编译器视其为1字节,另外编译器默认是按照4字节对齐的,所以总共12字节

G4.9版本的rb_tree源码

在这里插入图片描述

  • set,map,multimap和multiset的实现主要依赖于rb_tree
  • G2.9版本与G4.9版本主要区别在于,G4.9使用了Handler/Body模式
  • rb_tree初始长度为16字节(虽然侯捷老师说的是20字节,但是我自己实际测试下来应该是16字节才对),因为rb_tree的成员_M_parent,_M_right,_M_left,分别为4字节,_M_color是一个枚举类型,占4字节,所以总共16字节

(multi)set

(multi)set源码实现

G2.9版本的(multi)set源码

在这里插入图片描述

  • set/multiset以rb_tree作为底层结构,且value和key合一,因为key_type和value_type的类型都是Key,identity直接将key从value中分离出来
  • set的key独一无二,因此insert()调用rb_tree的insert_unique(),multiset的key可以重复使用,因此insert()调用rb_tree的insert_equal()
  • set/multiset不能通过调用iterator来修改key的值,因为set/multiset调用了rb_tree底部的const-iterator

(multi)map

(multi)map源码实现

G2.9版本的(multi)map源码

在这里插入图片描述

  • map/multimap以rb_tree作为底层结构,value对应的是data_type,key对应的是key_type,留意这里的value_type是pair<const Key, T>,也就是把value和key的类型整合成一个pair<const Key, T>来作为rb_tree的数值类型,所以之后需要用select1st<pair<const Key, T>>将Key和T分离出来
  • map的key独一无二,因此insert()调用rb_tree的insert_unique(),multimap的key可以重复使用,因此insert()调用rb_tree的insert_equal()
  • set/multiset不能通过调用iterator来修改key的值,但是可以修改data的值,因为map/multimap将rb_tree底部设置为pair<const Key, T>,所以Key不可以被任意调用修改

map的operator[]

在这里插入图片描述

  • map/multimap会二分查找对应的Key,如果Key在map/multimap对应的[first, last)的范围内的话(否则返回last),则会返回不破坏map/multimap的排列顺序的第一个Key对应的value的引用

注意事项

map和set的迭代器类型以及相关操作的时间复杂度
双向迭代器
随机访问每个元素 O(logn)
末尾插入删除元素 O(logn)
中间或开头删插元素 O(logn)
为何map和set的插入删除效率比用其他序列容器高?
map和set中所有元素都是以节点的形式来存储,插入删除操作只涉及到指针的转换,无需像vetor和deque一样考虑内存重新申请与拷贝
为何每次insert之后,以前保存的iterator不会失效?
每次执行插入和删除操作后,内存没有改变(当然被删除的那个元素本身已经失效了),所以对应的iterator也不会失效。
即如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值