STL中的RB-tree

set和map的底层结构都是红黑树,它们最后基本只是对红黑树接口的简单调用。

这里就主要来说一说红黑树。

1.红黑树的定义

红黑树首先是一棵二叉搜索树(BST),二叉的意思是每个节点最多有两个儿子,搜索的意思是根节点大于左儿子,小于右儿子。

在此基础上还要满足以下5个条件:

(1)只有红色和黑色2种节点

(2)根节点为黑色

(3)父子节点不能同时为红色

(4)任意节点,到达其叶子节点的所有路径包含的黑色节点个数相同

(5)空节点看作黑色节点

个人感觉整个红黑树最重要的部分就是先理解这个定义,看看它到底要告诉我们什么?为什么要这么做?下面我就来说说我的理解。

(1)只有红色和黑色2种节点

这一条很好理解,既然叫红黑树,那么就是将这种BST中的节点分为了2种,一种是红色节点,一种是黑色节点。

(3)父子节点不能同时为红色

这一条是对红色节点的限制,这样就保证了要加入红色节点必须加一层红色再加一层黑色,这样就保证了N黑>=N红

(4)任意节点,到达其叶子节点的所有路径包含的黑色节点个数相同

这一条是对黑色节点的限制,这样就保证了,单独看黑色节点的话,红黑树是一棵完美黑色平衡的树。

(3)、(4)节点合起来究竟要表达什么呢?

我的结论是,对于搜索性能的保证。

根节点到任意叶子节点的最长路径长度:N黑1+N红

根节点到任意叶子节点的最短路径长度:N黑2

由(3)可知,N红<=N黑

由(4)可知,N黑1=N黑2=N黑

所以最长长度<=最短长度*2

而一棵与红黑树节点总数相等的完全平衡树,其高度必定介于红黑树最长长度和最短长度之间。

那么红黑树的搜索效率必定至少是完全平衡树的一半。

(2)根节点为黑色

通过之后我们认识到,新加入的节点必定要为红色,因为如果为黑色,必定就破坏了条件(4),因为平白无故增加了一个黑色节点。

这个时候又要保证条件(3),那么就需要进行一些父子节点的颜色交换,将父亲变红,将儿子变黑。见后文3.(3)变色与旋转

这样可能导致红色不停地向上传递,最终传递到根节点,这个时候根节点会自己变为红色,然后将儿子设定为黑色。

然后每次插入结束,再把根节点置为黑色。如果一开始根节点就为红色,这种变化就完不成。

(5)空节点看作黑色节点

这个在插入节点要进行的旋转操作中可以看到,父亲和儿子同为红色旋转的时候,叔叔节点为红色是一种情况,叔叔节点为空或者为黑色是一种情况。

也就是说,节点为空和为黑色,可以当做一种情况来处理,所以空节点看作黑色节点也是理所当然的。

总结一下:

条件(2)保证了,条件(3)、(4)的成立

条件(3)、(4)才是最重要的条件,因为它们共同保证了,红黑树的搜索效率。


2.迭代器的移动

说到红黑树的迭代器,就不得不先说一下stl红黑树实现的时候的内部结构。

直接上图


在root节点之上还有一个header节点,这个节点可以看做是end节点。

它的left指向全树最小节点,用leftmost表示,同时它也是begin节点。

它的right指向全树最大节点,用rightmost表示。

header节点的父节点是root,同时root节点的父节点是header。

父节点的父节点是本身,并且是红色的就是header节点。

父节点的父节点是本身,并且是黑色的就是root节点。

header节点的引入是为了方便管理,使得迭代器符合[begin, end)规则。

迭代器的移动,也是要按着节点增大那样来移动。

下面说说边界情况。

①increment

++rightmost = end

++end 结果不确定,但是肯定是rb-tree中的节点

②decrement

--leftmost = end

--end = rightmost


3.插入节点

这里只讨论插入的节点是均不相同的情况。

(1)函数调用

insert_unique ==》 __insert ==》 __rb_tree_rebalance 

==》__rb_tree_rotate_left

==》__rb_tree_totate_right

(2)最终的处理

就是穷举了所有的情况,然后按照不同的情况来处理。

(3)变色与旋转

由之前的条件(4)可知,新加入的节点肯定是红色的,

①如果父亲是黑色,什么都不用做。

②如果父亲是红色,那么爷爷肯定是黑色,这个时候如果叔叔存在且也为红色,这个时候只需要将父亲和叔叔都变为黑色,然后将爷爷变为红色。

然后再往上迭代检查,最后将根节点置为黑色。

③如果父亲是红色,那么爷爷肯定是黑色,这个时候如果叔叔存在且为黑色或者叔叔不存在,就需要旋转。

旋转的时候也需要变色,以保证条件(4)。

(4)单旋转与双旋转


之所以会存在单、双旋转是因为,在旋转的过程中还必须首先保持红黑树是一棵BST,也就是说,根节点大于左节点且小于右节点。

(1)和(4)中间大小的节点恰好是P,所以单旋转就好。

(2)和(3)中间大小的节点却是X,所以需要双旋转。

所以红黑树的插入操作最多需要2次旋转。旋转复杂度为O(1)

(5)左旋转与右旋转

①左旋转

左子节点顶替父亲的位置,父亲作为原左子节点的右子节点

②右旋转

右子节点顶替父亲的位置,父亲作为原右子节点的左子节点


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值