复习红黑树(二)--红黑树的删除

红黑树的删除,是红黑树里面最麻烦的一个操作。。

红黑树的删除情况比较多,逐个分析

    首先复习一下红黑树的5个原则:
1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点,即空结点(NIL)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。
5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

     首先,红黑树也是一颗二叉搜索树,所以他的删除的开始步骤和普通的二叉搜索树是一样一样的。首先找出他的后继节点,然后将交换节点信息(颜色不换)。

     设他的后继节点是d,那么d节点,是真正要删除的节点,主要来分析d节点。

     首先,应该明确一点:d节点是要删除节点的后继节点(具体参考二叉搜索树的删除),所以d节点要么是删除节点左子树的最大值(没有右孩子),要么是右子树的最小值(没有左孩子)。

     再定义一个概念:  红黑树的叶子节点全是值为null的节点,在这里为了清晰把这种叶子节点叫假叶子,把左右孩子只有null节点的节点叫做真叶子。

     再来分析d节点:

     1) d节点是红色的。d节点或者有一个孩子,或者没有孩子(不包括假叶子节点),如果d有孩子,那么d的孩子一定是黑孩子(因为原则)。不妨设d有右孩子ad的左孩子是假叶子节点b,那么从根节点到d的右子树的假叶子节点的路径,其中的黑节点的个数一定比从根节点到假叶子节点b的黑节点个数多1(因为从db中间没有叶子节点,但是从da再到a的孩子,假叶子节点,中间有一个节点a)。

      所以,如果d节点是红色的,一定是真叶子节点,那么删除操作直接将d置为假叶子节点即可。

      2)d节点是黑色的,那么删除d节点,肯定会破坏原则5,这是最麻烦的地方,需要进行调整,使整棵树符合红黑树的几个原则。 

扫描二维码关注公众号,回复: 727142 查看本文章

      首先,要明确,我们调整树,是没有什么一定规则的,只要最后能把整棵树调整成红黑树,都是可以的,哪怕你无脑得把整棵树所有节点都变成黑的。。。  当然,要考虑效率问题,所以尽量少调整。   不过红黑树已经有各种大神研究了,所以调整方法基本上也就那么几种。

      删除了d节点,假设e 节点代替了d节点的位置,如下图

      那么,就要分析了。从根节点到e的路径,黑色节点少了一个,那么就要通过调整,要么在这条路径上加一个黑色节点,要么在其他所有的叶子节点路径减一个黑色节点。

      2.1 首先,如果e节点是d节点的红色孩子,那么直接把e染黑即可;

      2.2  如果e节点的兄弟节点是红色的,那么他的父亲必然是黑色的,通过旋转,把他变成黑色兄弟的情况,然后再分析调整,如图:



 
如图是e节点有个右兄弟,父节点和兄节点颜色互换,然后以右兄弟为轴逆时针转,变成了e节点有黑兄弟,2.4的情况,然后依2.3分析

    2.3 e节点的兄弟节点是黑色的:

    2.3.1 如果e节点的父亲是红色的,这种情况最简单,把父亲染黑,然后兄弟染红即可。因为父亲从红变黑,所以e节点这条线相当于黑节点个数不变。因为父亲从红变黑,兄弟从黑变红,所以相当于e节点的兄弟节点这条线黑节点个数也没变。。

 

    2.3.2  如果e节点是黑色的,他的父亲是黑色的,他的兄弟是黑色的,他的兄弟的孩子全是黑色的(他的兄弟肯定有孩子(包括假叶子节点))。。。   就是说三代内全黑。。那么,首先,以e的父亲为跟的子树,是不符合红黑树的标准的(因为e这棵子树少一个黑节点d),所以,首先要调整的,是让这棵子树变成红黑树。怎么变?   前边分析过了,除了d节点所在的路径外,其他的所有路径上都去掉一个黑节点就行了。   所以,令e节点(现在的d节点)的兄弟节点变成红色,然后把指针指向e节点的父亲,让e节点的父亲作为新的标准节点依次递归向上调整。这时候,以e节点父亲为跟的子树变成了红黑树,但是整体路径少了一个黑节点,向上调整至跟,或者调整结束,整棵树才会变成红黑树。

 



 
2.3.3 兄弟是黑色的,父亲是黑色的,但是侄子是红的。这种情况其实是可以利用2.3.2的方法,染色然后一直递归进行的。但是因为侄子里有红色的,是有调整空间的,所以可以优化为复杂的调整过程(过程虽然复杂,但是时间复杂度是常数,要优于过程简单的变色调整)。



 
如上图,当e点是父节点的右孩子,e节点兄弟节点的左孩子是红的,那么以兄弟为轴逆时针转,然后将侄子涂黑,变成右边的树。可以看到,这时候新树的根节点(兄)的左子树黑色节点数目没变,但是右子树(删除了一个黑节点的子树)黑色节点增加了一个,所以形成的新树是红黑树,调整完毕。

 



    
II   上图中,如果节点e是父节点的右孩子,e节点的兄弟节点的右孩子是红的,那么先将此节点染黑,然后以e的兄弟为轴先逆时针旋转,然后再以新的e节点的兄弟节点(原来的红色的侄子节点)为轴顺时针旋转,变成右边的树,调整完毕。 

     下面两图同理:

 



 

PS:   到现在,分析完毕了。首先需要说明的是,以上的各种情况,是if,else关系,就是说进入一中情况的代码以后,是不会进入另外一种情况了,所以应该选择尽量复杂度较少的情况优先进入。

  其次就是红黑树的调整比较麻烦,他的所有调整的目标就是那5大原则。只要最终形成符合那5大原则的树,怎么调整都是代码说了算。

 

 

 

 

猜你喜欢

转载自709002341.iteye.com/blog/2259560
今日推荐