rb_tree深度探索
rb_tree vs AVL树
- AVL是一个高度平衡的二叉树,而红黑树不是
- 红黑树每次插入一个元素,最多只需要两次旋转;而AVL可能需要更多次平衡操作
- 搜索速度:AVL树更加快,因为其严格遵守高度平衡,搜索查找的平均时间复杂度为log2(n)
- 插入速度:红黑树更加快,因为最多只需要两次旋转再加一些重新着色。
- AVL树是rb_tree的子集
红黑树的结构
-
红黑树是平衡二分搜索树中常常使用的一种,平衡二分搜索树的特性:排列规则有利search和insert,并保持适度平衡。
-
红黑树提供遍历的功能及iterators。按正常规则(++ite)遍历,便能获得排序状态。
-
红黑树的结构样例:

-
为红黑树的中序遍历,begin()在左下,end()是在右下
-
红黑树的规则(首先需要是一颗二分查找树{BST}):
- 1.每个节点不是红色就是黑色
- 2.根节点为黑色
- 3.如果节点为红,其子节点必须是黑(如果节点为黑,其子节点既可以是红也可以是黑)
- 4.任一节点至NULL(树尾端)的任何路径,所含黑色节点数必须相同

-
根据规则4,新增节点必须为红;根据规则3,新增节点之父节点必须为黑,当新节点根据二叉搜索树的规则到达其插入点, 但未能符合上述要求,就必须调整颜色并旋转树形
-
我们不应该用红黑树的iterators改变元素值(因为元素有其严谨的排序规则)。但是编程层面并未阻止此事,rb_tree将会为set和map服务,而map允许元素的data被改变, 只有元素的key才是不能被改变的。
-
rb_tree提供两种insertion操作(红黑树本身对重复与否没有限制,而取决于insert的方式):insert_unique()和insert_equal()。前者表示节点的key一定在整个树中独一无二, 否则安插失败;后者表示节点的key可以重复。
部分源码(在这里将key和data合起来的节点合成value):
cpp
//这里的Value是key和data的组合,如果value只传一个值说明没有value(set)
template <class Key, class Value, class KeyOfValue, class Compare,
class Alloc = alloc>
class rb_tree {
protected:
typedef __rb_tree_node<Value> rb_tree_node;//红黑树的结构
···
public:
// 注意,没有定义iterator(喔,不,定义在后面)
typedef rb_tree_node* link_type;//指向红黑树节点的指针
···
protected:
//rb_tree只以三个资料表现它自己
size_type node_count;//rb_tree的大小(节点数量)
link_type header;
Compare key_compare;//key的大小比较准则;应会是个function object
···
}
红黑树插入节点
红黑树插入的节点默认为红色,首先根据二叉树寻找插入的位置,再根据相对位置来调整红色和黑色,以及旋转的问题。
关于红黑树的插入问题,可以在这个网站 来手动插入试验一下!(Red/Black Tree Visualization)
- 关于红色和黑色节点的问题:
- 插入节点初始一定为红色,新增节点的父节点必须为黑色,再根据rb_tree的四条规则进行调整。
- 关于旋转,先看一个实例:

红黑树旋转的具体规则如下(假设插入的节点为X):
- 将新插入的节点标记为红色
- 如果 X 是根结点(root),则标记为黑色(2⃣️)
- 如果 X 的 parent 不是黑色,同时 X 也不是 root(3⃣️):
- 如果 X 的 uncle (叔叔) 是红色:
- 将 parent 和 uncle 标记为黑色
- 将 grand parent (祖父) 标记为红色
- 让 X 节点的颜色与 X 祖父的颜色相同,然后重复步骤2⃣️3⃣️
- 如果 X 的 uncle (叔叔) 是红色:
。。。STL_sourcecode/10.第十讲 at master · caixiongjiang/STL_sourcecode
Set,multiset剖析
set和multiset特性
- set/multiset以红黑树为底层结构,因此有自动排序的特性,排序的依据是key,而set和multiset的value和key 是合二为一的:value就是key(key和data合成value)
- set和multiset提供遍历的操作以及iterator,按照正常的规则遍历就能获得排序状态。
- 无法使用iterator来改变元素值(底层为将iterator设为const),因为key有其严谨的排序规则。
- set的key必须独一无二,因此其insert()用的是rb_tree的insert_unique()
- multiset元素的key可以重复,因此其insert()用的是rb_tree的insert_equal()
multiset容器
除了multiset之外和set基本没有区别
map和multimap特性
- rb_tree为底层结构,因此有元素自动排序功能,排序的依据依然为key
- 提供iterator,正常遍历便能获得排序状态的结果
- 无法使用iterators来改变元素的key,但可以用来改变元素的data。(底层为将key值设为const类型)
- map的key必须独一无二,因此其insert()用的是rb_tree的insert_unique()
- multimap元素的key可以重复,因此其insert()用的是rb_tree的insert_equal()
map独特的operator\[\]
- operator\[\]的作用为返回对应key的data值,如果这个key不存在,标准库将会自动创建该key值放入map中
- 源码层:使用lower_bound来寻找元素的key值,如果找到则返回迭代器进行操作;如果没有找到则呼叫insert()
- lower_bound是二分查找的一种版本,试图在已经排序的范围[first, last)中寻找一个元素值,如果找得到就返回 一个iterator指向其中的第一个符合条件的元素值;如果没有找到则返回last的iterator(最适合安插这个值的位置)
- operator\[\]创建新的key比直接使用insert插入效率低,因为前面还多了一步lower_bound的过程
heap&priority_queue深入探索
STL_sourcecode/13.第十三讲 at master · caixiongjiang/STL_sourcecode