红黑树的另一个重要的操作是删除节点,它也可以分为两步:
- 找到要删除的节点,并删除它
- 对树进行调整使得树满足红黑树的要求
一、删除节点
从排序树中删除节点的思路是一样的,首先找到要删除的节点,并做如下处理:
- 如果该节点不存在非空子节点,则直接删除它
- 如果该节点存在一个非空子节点,则用其非空子节点替换其位置即可
- 如果该节点有两个非空子节点,则可以找到该节点的前驱或者后继,然后更换两个节点的元素值,再将前驱或者后继当做被删除的节点(由于任意一个节点的前驱或者后继都必定至多只有一个非空子节点,因而删除这样的节点就可以按照前两种情形进行处理)
红黑树也采取了类似的思路,假设要删除的节点为A,则先找到节点A,然后:
- 如果节点A有两个非空子节点,则找到节点A的前驱(也可以是后继),然后记要删除的元素B=A的前驱
- 否则只要A有一个空子节点,就记要删除的元素B=A
- 记变量X为B的第一个非空子节点(先检查左孩子,后检查右孩子),如果B的两个孩子都为空,则记X为空
- 如果B和A不同,则将B的内容拷贝到A
- 删除节点B
- 如果被删除节点B的颜色为红色,则删除结束,否则从节点X处开始对删除节点后的红黑树进行调整
以下图为例:
- 如果要删除节点75,则A=75,B=85,X=NULL
- 如果要删除节点25,则A=25,B=19,X=NULL
- 如果要删除节点40,则A=B=40,X=NULL
显然,在这种处理方式下,如果B的颜色为红色,则删除它后删除操作即完成了,因为:
- B是红色的,因而它不是根
- B是红色的,它的父节点必然是黑色的,因而删除它不会引入两个红色的连续节点
- B是红色的,而且它至多有一个非空子节点,因而删除它不会导致红黑树的任意路径上的黑节点数目变化
如果B的颜色为黑色,则需要从节点X处开始对删除节点后的红黑树进行调整。
二、红黑树删除后的调整
删除节点后的调整要根据N的不同情形来分情况处理(根据第一节的内容显然,这里的N指的就是第一节中的节点X)。假设删除节点后的树中,N的父节点为P,兄弟节点为S,兄弟节点的左孩子为SL,兄弟节点的右孩子为SR。需要注意的是空节点是有颜色的,它是黑色的。
2.1 N为根节点
这种情形非常简单,直接将其修改为黑色即可。因为如果N原来是黑色,则这样做不会改变其性质,如果原来为红色,我们需要保持红黑树的性质,也要把它修改为黑色。
2.2 N节点为红色
空节点不可能是红色的,而按照我们删除时所采取的算法,此时的N必定为被删除的黑色节点的唯一非空子节点,并且在删除后它替代了被删除节点的位置,那么要恢复红黑树的性质就非常简单,只要将其颜色修改为黑色即可。
2.3 N、S、SL、SR、P都为黑色
如下图所示:
此时的做法是将S的颜色修改为红色,则通过S和通过P的路径上的黑色节点数目变得相同了,但是通过N的路径比不通过N的路径都少了一个黑色节点,因而需要将P节点看做N节点重新执行调整算法。
调整完后如下图所示:
2.4 N、S、SL、SR都为黑色,P为红色
如下图所示:
此时的处理很简单,只需要将S和P的颜色互换即可完成调整。
调整完可以得到下图:
在S和P的颜色互换后,P成为了黑色,它为经过节点N的路径添加了一个黑色节点从而补偿了被删除的黑色节点;同时由于S的两个孩子都为黑色,因而S改为红色也不会导致两个连续的红色节点,由于S的黑色只是上移到了其父节点P上,因而经过S节点的路径的黑色节点数目也不会发生改变。
2.5 N是黑色,S是黑色,SR是红色(考虑N为P的左孩子的情形,N为P的右孩子的情形与之对称)
此种情形如下图所示:
此时的做法:
- 将以P为根的子树进行左旋
- 交换P和S的颜色
- 将SR的颜色改为黑色
则可以得到下图:
- 对原树中P的父节点来说,调整前后其孩子的颜色没有改变,而N,P,S,SL,SR在调整之后也没有出现连续的红色节点,因而不允许出现连续红色节点的性质没有被违背。
- 对于N,P,S,SL,SR这几个节点组成的树的部分来说,调整后它们给经由节点N的路径贡献的黑色节点数目比调整前增加了一个,这恰好补偿了删除黑色节点的效果;而对于不经过N节点但是又经过其它几个节点中的任意一个的路径来说,它们贡献的黑色节点数目不变。
因而调整完成。
2.6 N是黑色,S是黑色,SL是红色,SR是黑色(考虑N为P的左孩子的情形,N为P的右孩子的情形与之对称)
此种情形如下图所示:
此时的做法是:
- 首先对以S为根节点的子树进行右旋
- 然后交换S和SL的颜色,即S改为黑色,SL改为红色
则可以得到下图:
由于节点SL的左孩子在旋转前后不变,而SL原来为红色,所以SL的左节点必然为黑色,因而旋转后,对于N节点来说,这就是情形5,按照情形5进行处理即可。因此总体上来说这种情形需要一次左旋,一次右旋。
2.7 N是黑色,S为红色(考虑N为P的左孩子的情形,N为P的右孩子的情形与之对称)
由于S为红色,所以P,SL,SR都必定为黑色,如下图所示
此时的做法是:
- 首选对以P为根节点的子树进行左旋
- 然后再将S和P的颜色互换,即修改S的颜色为黑色,P的颜色为红色
则可以得到下图:
这就把该情形转化成了N为黑色,其兄弟为黑色的情形,再根据具体的情形参考情形3,4,5,6进行处理即可。