本文主要说明红黑树的插入和删除操作。
红黑树是满足以下性质的二叉搜索树:
1. 每个结点颜色或黑或红。
2. 根结点是黑色。
3. 每个叶结点(nil)为黑色。
4. 如果一个结点是红色,那么它的两个子节点都是黑色的。
5. 对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点。
为了便于处理红黑树中的边界条件,使用一个颜色为黑色、其他属性任意的结点T.nil最为哨兵结点,让root的p和叶结点的left, right都指向T.nil。
插入操作:
设X为已经插入的结点,P为X的父结点,G为X的祖父结点,U为G的另一个子结点,即X的叔结点。
先将要插入的结点颜色设为红色,按照普通步骤插入结点之后可能破坏红黑树的性质,所以要进行修正。
破坏的性质可能是:
1. X和P都是红色,违反了性质4。
2. X是root,违反了性质2。
情况二只要将root重新变为黑色即可,下面主要考虑情况一。
如果P是G的左孩子,情况一的修正情况分为:
1. G为红色,P和U均为黑色:将G变为黑色、P和U变为红色即可。这种情况不用区分X是P的左孩子还是右孩子。完成之后虽然确保了X和P不是相邻的两个红色结点,但是G和G的父结点却又有可能称为相邻的红结点,所以将G变为X,进入下一轮循环。
2. G为黑色,P为红色,X为P的右孩子:将P左旋,变成情况3。这种情况不用考虑U的颜色。
3. G为黑色,P为红色,X为P的左孩子:将G变为红色,P变为黑色,并将G右旋。此时整个修正过程结束。
如果P是G的右孩子,又有三种情况,和这个是对应的。
(我懒得放图片了,详情请看算法导论)
删除操作:
每次删除过程是先找到要删除的结点(设为A),然后找这个结点的中序后继(设为B),将中序后继B和被删结点A替换,再替换颜色(相当于将中序后继和被删结点的除颜色外的属性全部互换)。这样被删结点就变成了最多只有一个孩子情况,之后用右孩子(设为X)替换这个被删结点(当然如果和中序后继替换之前的被删结点本来就只有一个孩子,也可以直接用另外一个孩子替换)。
如果B颜色为红,则可以直接删除,没有影响。
但是如果B颜色为黑,就可能违反了任意结点到叶结点过程中经过黑色结点的个数相同这个性质。
设X的父结点为P,X的兄弟结点是S,S的左儿子为SL,S的右儿子为SR。
下面说明如果B为黑色,要如何进行修正。之前说过用B的右孩子替代B,所以现在情况是从root到以X为根的子树的叶结点过程中经过的黑色结点少一个,解决的办法一是让X变成黑色,或通过某种办法找到某个合适的、现存的结点插入到X和P之间或让S子树的黑色结点少一个,之后将X向上传递,最后到达root,这样到达所有叶结点过程中经过黑色结点的数量都减少了一(说的可能不太清除,但总的来说就是这样了)。
如果X是P的左儿子,修正分为以下几种情况:
1. 如果X为红色:直接将X变为黑色。
2. 如果X为黑色,S为红色:将S变为黑色,P变为红色,再将P左旋,重新定义S为P的右儿子,根据SR和SL进入下面三种情况中的一种。(正常情况下和一个红色结点的相连的结点肯定是黑色的,所以P一定是黑色)
3. 如果X为黑色,S, SL, SR均为黑色:将S变为红色,冲新定义X为P,进入下一轮循环。(效果是将X向上传递)
4. 如果X为黑色,S, SR为黑色,SL为红色:将S变为红色,SL变为黑色,将S右旋,之后交给下一种情况处理。
5. 如果X为黑色,S为黑色,SR为红色:将S变为红色,P变为黑色,SR变为黑色,再将P左旋,处理结束。(效果是原来P的地方和X之间多了一个黑色结点)
来源:https://www.cnblogs.com/nonoo/p/12389428.html