红黑树详解
红黑树的详解
- 定义
- 定理
- 删除
现来说一下以下文章中一些默认的语言是什么意思。
叔叔节点中远离当前节点的节点是红色
在这里插入图片描述
而且注意以下讨论都没有对称的去讨论,也就是说当讨论节点在左侧的时候讨论和在右侧的时候讨论一样。所以我们只讨论一种情况
1.定义
- 节点是红色或黑色。
- 根节点是黑色。
- 每个叶节点是黑色的(这里的叶节点是指NULL节点,并不是真正意义上的叶节点)。(注意在已下讨论中我们可能不会过多的关注NULL节点,)
- 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径5. 上不能有两个连续的红色节点,或者理解为红节点不能有红孩子)
- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点(黑节点的数目称为黑高black-height)。
2.优劣势
- 一棵含有n个节点的红黑树的高度至多为2log(n+1).
- 查找的时间复杂度为O(log(n)),最差情况下要比AVL稍逊一些。
- 插入最多需要2此旋转,变色需要O(log(n))
- 删除操作最多需要3次旋转,而AVL需要O(log(n))此
关于这里,写者本来写了插入操作以及为什么插入操作最多旋转2次和颜色变换时间复杂度证明,也点了保存,但是网络并没有给我保存上。
所以关于插入所有证明以及一些坑还有删除操作为什么最多3次都没有保存。插入操作并不难。难得是为什么旋转不超过2次。鉴于写者最近时间繁忙,所以不会补全这一段内容了,仅仅补全删除操作最多3次得证明。读者可以参考删除操作得旋转为什么最多不超过3次去思考下为什么插入旋转不超过2次
3.删除操作
红黑树的删除操作借鉴了二叉树搜索树的删除操作,也就是找到删除节点的后继节点,然后将后继节点的值赋给删除节点,然后删除后继节 点就可以(我们以下说被删除的叶节点的时候往往指真正删除的节点而不是我们想要去删除的节点,结合二叉搜索树想想这句话)。但这样可能会破坏红黑树的定义,主要是会导致(4)和(5)。
被删除的节点只能会是两种情况
- 单个的叶子节点(不是指NULL)
- 只有右子树(或只有左子树)的节点
现在来看,如果被删除的节点只能是黑色节点或者是红色节点我们分情况讨论。
(1)被删除节点是红色的,那么这个红色节点一定是叶节点,因为如果这个节点还有左孩子或者是右孩子都不符合定义,如果孩子是红色节点,那么破坏(4),如果孩子黑色节点,那么破坏(5)。显然删除红色叶子节点没有任何影响。
如果被删除的节点是黑色的,那么就比较复杂了,现在来具体的分析
(2)被删除的节点是黑色节点
3. 如果被删除的黑色节点有左孩子的话,那么他的左孩子一定是红色节点且左孩子没有孩子。(如下图,白色代表什么红黑节点都可以,竖直连线代表其他是父节点的左孩子还是右孩子都可以)
这种情况下删除黑色的节点只需要把红色的节点挂到白色的节点下面然后变成黑色节点就可以。
4. 如果被删除的节点有右孩子的话,那么同理。
5. 如果被删除的节点没有叶子节点的话
- 如果删除节点的兄弟节点位红色,那么他们的父节点一定是黑色,且兄弟节点一定有两个黑色孩子节点。如下图
这个时候就是将红色的节点变成黑色,红色节点的父节点变成红色,然后左旋转
注意此时最左下面的节点是待删除的节点,这个时候就把待删除的节点的兄弟节点变成黑色的了,注意在整个变化过程中我们并没有破坏(5)(可以认真的思考下),必须要注意,这时候我们没有删除D节点,这一步的操作只是让其变为已下的几种情况再去处理,也就是让他的兄弟节点变成黑色。 - 然后我们来考虑下第二种情况,也就是兄弟节点是黑色,兄弟节点的远离自己的那个孩子是红色,不远离自己的那个孩子只能是红色或者没有,如下图)D节点是待删除的节点,我们可以让上面的树左转,然后让S代替P的地位,也就是让S变成P原来的原色,让P代替D变成黑色,SR变成黑色代替S的地位,仔细思考一下,变换后的树也没有破坏任何定义,如下图
注意没有讨论待删除的节点在右边的时候,待删除的节点在右边的时候同理。 - 兄弟节点为黑色,其离待删除节点近的那个孩子为红色,远的那个孩子为空。(注意此时如果离待删除的那个节点不为空的话那么他一定为红,这样的话就变成上一个情况了),如下图
这个时候可以把他变成2情况,直接右旋就行。然后将S和SL的颜色互换一下就行了。
同理,待删除节点在右边的情况同理。 - 当兄弟节点为黑色,且没有任何孩子的时候,父节点为红色的时候。这时如下图所示,只需要把D删除,然后把P节点改成红色,S节点变成黑色就可以了。
- 然后就是最后一种情况,兄弟节点是黑色且没有孩子,父亲是黑色。这个时候直接将S变成红色,这个时候经过P的路径中黑色节点的个数少了一个,怎么办呢?把P当做当前要处理的节点,那么情况就变成了以上的几种,这时候我们只是把D删除,然后把P当成D看待而已,并不在以后的操作中真正的删除P。尽管以上的讨论均是在D仅有一个孩子或者是叶节点的时候讨论的,但可以自己验证,以上的几种操作对于带着孩子的D也是可行的。所以我们可以将P当称D抽象的调用以上的几种方法。
现在证明关于删除操作得旋转不超过3次。
我们知道情况4不需要旋转,直接变下颜色后结束。情况2直接旋转1次后结束。情况3旋转1次变到情况2后再旋转1次结束,这种情况一共旋转2次。情况1旋转过后可能会变成情况2,3,4,我们都讨论过了。情况5不需要旋转,但他需要递归下去,变成情况12345继续讨论。如下图
最多得变换是走这条路1->3->2。这条路会3次旋转,但是他的前面可能会有n中情况5得递归如5->5->5->…->1->3->2。其他得情况得旋转次数都小于3.另外情况5一直递归调用情况5那么颜色得复杂度不难想出是O(log(n))。如果不是情况5一直调用情况5得话(当然情况5也会再调到根节点结束),进入到其他任何一种情况都会在有限得几步之内结束。
另外以上当删除节点是黑色节点且没有孩子得时候得所有图像中。D节点下面可以有孩子也可以没有孩子。读者可以想想我们再情况5结束后继续调用得时候是不是把P当成D,此时D得下面是不是有孩子?为什么画得时候要画没孩子,我们仔细想想,因为我们一开始讨论的时候并布什从5递归调用过来的。而我刚刚所说不管D有孩子是指得是情况5递归调用得时候仍然可以使用情况12345,所以D有没有孩子都解释的通!