全部博文(60)
分类: LINUX
2016-04-17 17:03:24
从红黑树上删除一个节点,可以先用普通二叉搜索树的方法,将节点从红黑树上删除掉,然后再将被破坏的红黑性质进行恢复。
我们回忆一下普通二叉树的节点删除方法:Z指向需要删除的节点,Y指向实质结构上被删除的结点,如果Z节点只有一个子节点或没有子节点,那么Y就是指向Z指向的节点。如果Z节点有两个子节点,那么Y指向Z节点的后继节点(其实前趋也是一样的),而Z的后继节点绝对不可能有左子树。因此,仅从结构来看,二叉树上实质被删除的节点最多只可能有一个子树。
现在我们来看红黑性质的恢复过程:
如果Y指向的节点是个红色节点,那么直接删除掉Y以后,红黑性质不会被破坏。操作结束。
如果Y指向的节点是个黑色节点,那么就有几条红黑性质可能受到破坏了。首先是包含Y节点的所有路径,黑高度都减少了一(第5条被破坏)。其次,如果Y的有红色子节点,Y又有红色的父节点,那么Y被删除后,就出现了两个相邻的红色节点(第4条被破坏)。最后,如果Y指向的是根节点,而Y的子节点又是红色的,那么Y被删除后,根节点就变成红色的了(第2条被破坏)。
其中,第5条被破坏是让我们比较难受的。因为这影响到了全局。这样动作就太大太复杂了。而且在这个条件下,进行其它红黑性质的恢复也很困难。所以我们首先解决这个问题:如果不改变含Y路径的黑高度,那么树的其它部分的黑高度就必须做出相应的变化来适应它。所以,我们想办法恢复原来含Y节点的路径的黑高度。做法就是把Y节点的黑色,推到它的子节点X上去。(X可能是NIL节点)。这样,X就可能具有双重黑色,或是同时具有红黑两色,也就是第1条性质被破坏了。
但第1条性质是比较容易恢复的:一、如果X是同时具有红黑两色,那么好办,直接把X涂成黑色,就行了。而且这样把所有问题都解决了。因为将X变为黑色,2、4两条如果有问题的话也会得到恢复。二、如果X是双黑色,那么我们希望把这种情况向上推一直推到根节点(调整树结构和颜色,X的指向新的双黑色节点,X不断向上移动),让根节点具双黑色,这时,直接把X的一层黑色去掉就行了(因为根节点被包含在所有的路径上,所以这样做所有路径同时黑高减少一,不会破坏红黑特征)。
下面就具体地分析如何恢复1、2、4三个可能被破坏的红黑特性:我们知道,如果X指向的节点是有红黑两色,或是X是根节点时,只需要简单的对X进行一些改变就行了。要对除X节点外的其它节点进行操作时,必定是这样的情况:X节点是双层黑色,且X有父节点P。由知可知,X必然有兄弟节点W,而且这个W节点必定有两个子节点。(因为这是原树满足红黑条件要求而自然具备的。X为双黑色,那么P的另一个子节点以下一定要有至少两层的节点,否则高黑度不可能和X路径一致)。所以我们就分析这些节点之间如何变形,把问题限制在比较小的范围内解决。另一个前提是:X在一开始,肯定是树底的叶节点或是NIL节点,所以在递归向上的过程中,每一步都保证下一步进行时,至少 X的子树是满足红黑特性的。因此子树的情况就可以认为是已经正确的了,这样,分析就只限制在X节点,X的父节点P,X的兄弟节点W,以及W的两个子节点。这些个节点中。
W以及W的两个子节点C1和C1的一共有五种组合,便有两种情况的处理是一致的,因此调整的过程可以分以下四个情况:
第一种情况:W是红色节点
如上图,如果W是红色的,那么B和D节点进行一次左旋,并把D(也就是原来的W)着为黑色,B节点(X的父节点)着为红色。然后让W指向X的新兄弟。这样,就把这种情况转化为了W为黑色的情况来解决。在这个变形中,这五个节点之间保持了红黑性质不变,而X指向的双黑色节点的位置和颜色特性都没有变化。变形后的情况如何解决呢?下面的都是W为黑色的问题,因此下面三种中总有一种会合适。
PS:有没有其它变形呢?有,比如C和D进行右旋,B节点变为红色,变形后五个节点红黑正确的,但是这五个节点与树的其它部分相接处可能会产生问题,这样要考虑的因素就太多了。
第二种情况:W以及W的两个子节点都是黑色的
如上图,注意,B即可以是红色也可以是黑色。
这种情况下,把D节点着成红色。然后把X的一个黑色推到父节点B中去,这时X就指向B节点了。变形前后,这五个节点间的黑高是没有变化的。
唯一可能产生问题的就是如果B原来是红色,那么B和D两个红色相邻就破坏了第4个性质,这样新X的子树就有问题了。这本来不符合我们向上递归的假设。但正好在这种情况下递归就可以结束了。因为B节点原来是红色,现在双加一层黑色,那么X现在指向的这个节点就是红黑两色的,直接把X(也就是B)着为黑色。问题就已经完整解决了。
如果B节点现在是双层黑色,那就以B为新的X进行向上的下一次的递归。
第三种情况:W的左子节点是红色的且右子节点是黑色。
如上图,B即可以是黑色也可以是红色。
把C和D进行一次旋转,改变C和D的颜色变形成新的结构。把问题转化成W的右子节点为红色的情况来解决。注意,原来C是红色的,所以C的子节点一定是黑色的,所以旋转中C节点的一个子树挂到之后着为红色的D节点上不会破坏红黑性质。变形后黑高度不变。
第四种情况:W的右子节点是红色(左子节点可以是红色或黑色)
如上图,B节点可以是红色或是黑色。
将B和D进行一次左旋,并交换两者的颜色。再将E着为黑色。这时,只要将X的一层黑色脱去,整个问题也得到了解决。递归结束。(在代码上,为了标识递归结束,我们把X指向根节点)
因此,只要按上面四种情况一直递归处理下去,X最终总会指向根结点或一个红色结点,这时我们就可以结束递归并把问题解决了。
以上就是红黑色的节点删除过程。