本文是对《算法导论》第三版第十三章红黑树删除操作的解读。书中用一个结点有两种复合颜色来分析,但是它的伪代码中并没有体现这个概念,读起来让人费解,因此本文不使用书中的解释,而是参考书中伪代码和图例,用更直白的语言来描述整个过程。
基本情况
下面是第183页RB-DELETE(T,z)伪代码的解读,删除操作会分为以下3种情况:
-
被删的z左子结点为空,则右子结点顶上z的位置。(对应伪代码第3-5行)
- 如果z是红色,则结束。
- 如果z是黑色,则分析右子结点(z.right),书中为x。
- 因为删了z会导致路径上少了一个黑色结点,所以右子树(z.right)要补上一个黑色结点,让红黑树重新达到完美平衡。
- 如果x是红色的,直接把它变成黑色,相当于增加一个黑色结点,直接不走RB-DELETE-FIXUP的while循环把x设置为黑色,结束。
- 如果x是黑色的,通过变换从x的兄弟结点调一个黑色的过来,请看下面的RB-DELETE-FIXUP。
-
被删的z右子结点为空,则左子结点顶上z的位置。(对应伪代码第6-8行)
-
如果z是红色,则结束。
-
如果z是黑色,则分析左子结点(z.left),书中为x。
- 因为删了z会导致路径上少了一个黑色结点,所以左子树(z.left)要补上一个黑色结点,让红黑树重新达到完美平衡。
- 如果x是红色的,直接把它变成黑色,相当于增加一个黑色结点,直接不走RB-DELETE-FIXUP的while循环把x设置为黑色,结束。
- 如果x是黑色的,通过变换从x的兄弟结点调一个黑色的过来,请看下面的RB-DELETE-FIXUP。
-
-
从z的右子树找出最小值y,来替代z。(也可以用z的左子树的最大值替代z,都行)因为y是z右子树的最小值,则y必定没有左子结点。(对应伪代码第9-11行)
-
如果y是z的右子结点。(对应伪代码第12、13、17-20行)
-
y顶替z的位置,y继承z的颜色。y的右子结点x顶替y的位置。
- 如果y原来的颜色是红色,那z是黑色的,x也是黑色的,因为不能有连续红色。y继承z的颜色,也就是少了原来y的红色,不影响,结束。
- 如果y原来的颜色是黑色,替换z之后会出现4中情况,1y黑x黑、2y红x黑、3y黑x红、4y红x红,路径上都会少一个黑色结点,通过变换从x的兄弟结点调一个黑色的过来,请看下面的RB-DELETE-FIXUP。
-
-
如果y不是z的右子结点,而是更下面的结点。(对应伪代码第14-20行)
- y继承z的颜色。如果y原来是红色,那不管z原来什么颜色,路径上只会少了y原来的红色,所以不影响,结束。
- y继承z的颜色。如果y原来是黑色,路径上就会少一个黑色结点,通过变换从x的兄弟结点调一个黑色的过来,请看下面的RB-DELETE-FIXUP。
-
RB-DELETE-FIXUP
至此,我们已经解决大部分问题,只剩下因为路径上少一个黑色结点,怎样通过变换从x的兄弟结点调一个黑色的过来这个问题,即P185的RB-DELETE-FIXUP伪代码要解决的问题,但这一段伪代码不完整,最好从官网下载Python Code来对照阅读。
下面是解决这个问题要采取的步骤:(下面的情况对应P186图13-7)
-
把红色的sibling(w)变成黑色。(对应情况1)
-
sibling(w)已经变成黑色或原来就是黑色,分4种情况(第三第四种情况合并为1种情况)
-
w左右结点都是黑色(对应情况2)
- 把w变红,这样就把从x的sibling中挪一个黑色结点变成从x.parent的sibling中去挪结点。这时会重新进入循环,重新从步骤1开始执行。
-
w左结点红、右结点黑(对应情况3)
- 把w的右子结点变成红色,进入下面这种情况。
-
w右结点红、左结点红或黑(红黑都无所谓)(对应情况4)
- 通过旋转变色,给x路新增黑色结点,结束。
-
除了2.1.这个步骤,其他情况都要执行到达2.3.即情况4才能结束。2.1.(对应情况2)这个步骤稍微复杂一点,看下面详细分析。(下面的情况对应P186图13-7)
-
情况1
- 执行转换动作。虽然没有改变路径上黑色的数量,但是转换成了其他能够做出添加黑色结点的情况。
- 把红色的sibling变成黑色。则x和sibling都是黑色。情况234都符合x和sibling都是黑色。
-
情况2
-
原本是A这条路少一个黑色结点,现在把D变成红色,则B下面的两条路都少一个黑色结点,那么就把原本A路少一个黑色结点转变成B路少一个黑色结点,即要给A路增加一个黑色结点转变成给B路增加一个黑色结点。
-
B结点可红可黑
- 红色时,转换之后的新x因为是红色,会退出循环,直接把x设为黑色,相当于增加一个黑色结点,结束。
- 黑色时,如果循环后碰到情况34,就按情况34的步骤走。如果x一直上移到root的过程中都没有碰到情况34(x上移指的是从原来A是x变成B是x,看图13-7),因为每次上移都会把新的x的sibling变红色,意味着整棵树的叶子结点(NIL)到root的距离比执行删除操作前减1。也就是这里不是从其他地方挪一个黑色结点过来以维持红黑树平衡,而是从其他地方减少一个黑色结点来维持红黑树平衡。
-
-
情况3
- 执行转换动作。虽然没有改变路径上黑色的数量,但是转换成了其他能够做出添加黑色结点的情况。(同case1)
- 目的:把w的右子结点变成红色。
-
情况4
- 通过其他的情况转换到本情况,执行新增一个黑色结点的操作。
以上就是红黑树的删除操作,还是看不懂的话,可以先看完P166二叉搜索树的删除操作,再看红黑树的删除操作,这样会更加清晰一些。