链接:https://www.cnblogs.com/qingergege/p/7351659.html
上一篇文章中讲了如何向红黑树中添加节点,也顺便创建了一棵红黑树。今天写写怎样从红黑树中删除节点。
相比于添加节点,删除节点要复杂的多。不过我们慢慢梳理,还是能够弄明白的。
回顾一下红黑树的性质
红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
节点是红色或黑色。
根节点是黑色。
每个叶节点(这里的叶节点是指NULL节点,在《算法导论》中这个节点叫哨兵节点,除了颜色属性外,其他属性值都为任意。为了和以前的叶子节点做区分,原来的叶子节点还叫叶子节点,这个节点就叫他NULL节点吧)是黑色的。
每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点,或者理解为红节点不能有红孩子)
从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点(黑节点的数目称为黑高black-height)。
首先先说一下我们要删除节点的类型
我们要删除的节点类型从大的方面来说,只有两种:
1、 单个的叶子节点(不是指NULL节点,就是二叉排序树中的叶子节点的概念)
2、 只有右子树(或只有左子树)的节点
为什么这样呢?
我们知道,对于一棵普通的二叉排序树来说,删除的节点情况可以分为3种:
1、 叶子节点
2、 只有左子树或只有右子树的节点
3、 既有左子树又有右子树的节点。
我们知道对于一棵普通二叉树的情况3来说,要删除既有左子树又有右子树的节点,我们首先要找到该节点的直接后继节点,然后用后继节点替换该节点,最后按1或2中的方法删除后继节点即可。
所以情况3可以转换成情况1或2。
同样,对于红黑树来讲,我们实际上删除的节点情况只有两种。
对于情况2,也就是待删除的节点只有左子树或这有右子树的情况,有很多组合在红黑树中是不可能出现的,因为他们违背了红黑树的性质。
情况2中不存在的情况有(其中D表示要删除的节点,DL和DR分别表示左子和右子):
1、
2、
3、
4、
上面这四种明显都违背了性质5
5、
6、
5和6两种情况明显都违背了性质4
此外对于删除红色节点的情况比较简单,我们可以先来看看。
我们上面把待删除的节点分成为了两种,那这里,对于删除的红色节点,我们也分两种:
1、 删除红色的叶子节点(D表示待删除的节点,P表示其父亲节点)
上面这两种情况其实处理方式都一样,直接删除D就好!
2、 删除的红色节点只有左子树或只有右子树
上面已经分析了,红黑树中根本不存在这种情况!!
接下来我们要讨论删除最复杂的情况了,也就是删除的节点为黑色的情况
同样,我们也将其分成两部分来考虑:
1、 删除黑色的叶子节点
对于这种情况,相对复杂,后面我们再细分
2、 删除的黑色节点仅有左子树或者仅有右子树
去掉前面已经分析的不存在的情况。这种情况下节点的结构只肯能是
(竖直的西线代替了左右分支的情况)
这两种情况的处理方式是一样的,即用D的孩子(左或右)替换D,并将D孩子的颜色改成黑色即可(因为路径上少了一个黑节点,所已将红节点变成黑节点以保持红黑树的性质)。
所以,这些情况处理起来都很简单。。。除了,删除黑色叶子节点的情况。
下面重点讨论删除黑色叶子节点的情况
情况1:待删除节点D的兄弟节点S为红色
D是左节点的情况
调整做法是将父亲节点和兄弟节点的颜色互换,也就是p变成红色,S变成黑色,然后将P树进行AVL树种的RR型操作,结果如下图
这个时候我们会发现,D的兄弟节点变成了黑色,这样就成后面要讨论的情况。
D是右节点的情况
将P和S的颜色互换,也就是将P变成红色,将S变成黑色,然后对P进行类似AVL树的LL操作。结果如下图:
此时D的兄弟节点变成了黑色,这样就成了我们后面要讨论的情况
情况2:兄弟节点为黑色,且远侄子节点为红色。
D为左孩子对的情况,这时D的远侄子节点为S的右孩子
没有上色的节点表示黑色红色均可,注意如果SL为黑色,则SL必为NULL节点。
这个时候,如果我们删除D,这样经过D的子节点(NULL节点)的路径的黑色节点个数就会减1,但是我们看到S的孩子中有红色的节点,如果我们能把这棵红色的节点移动到左侧,并把它改成黑色,那么就满足要求了,这也是为什么P的颜色无关,因为调整过程只在P整棵子树的内部进行。
调整过程为,将P和S的颜色对调,然后对P树进行类似AVL树RR型的操作,最后把SR节点变成黑色,并删除D即可。
D为右孩子的情况,此时D的远侄子为S的左孩子
同样,将P和S的颜色对调,然后再对P树进行类似AVL树RL型的操作,最后将SR变成黑色,并删掉D即可。结果如下图:
情况3:兄弟节点S为黑色,远侄子节点为黑色,近侄子节点为红色
D为左孩子的情况,此时近侄子节点为S的左孩子
做法是,将SL右旋,并将S和SL的颜色互换,这个时候就变成了情况4。
D为右孩子的情况,此时近侄子节点为S的右孩子
做法是将S和SR颜色对调,然后对SR进行左旋操作,这样就变成了情况4,结果如下图:
情况4:父亲节p为红色,兄弟节点和兄弟节点的两个孩子(只能是NULL节点)都为黑色的情况。
如果删除D,那经过P到D的子节点NULL的路径上黑色就少了一个,这个时候我们可以把P变成黑色,这样删除D后经过D子节点(NULL节点)路径上的黑色节点就和原来一样了。但是这样会导致经过S的子节点(NULL节点)的路径上的黑色节点数增加一个,所以这个时候可以再将S节点变成红色,这样路径上的黑色节点数就和原来一样啦!
所以做法是,将父亲节点P改成黑色,将兄弟节点S改成红色,然后删除D即可。如下图:
情况5:父亲节点p,兄弟节点s和兄弟节点的两个孩子(只能为NULL节点)都为黑色的情况
方法是将兄弟节点S的颜色改成红色,这样删除D后P的左右两支的黑节点数就相等了,但是经过P的路径上的黑色节点数会少1,这个时候,我们再以P为起始点,继续根据情况进行平衡操作(这句话的意思就是把P当成D(只是不要再删除P了),再看是那种情况,再进行对应的调整,这样一直向上,直到新的起始点为根节点)。结果如下图:
至此,所有的情况都讨论完了
总结一下(自己总结,难免有误):
红黑树的删除最终会转换为,删除叶子节点,或者删除只带一个右子树的节点,被删除节点,分为两类,(1)红色节点,直接删除,位置由后续节点补上。(2)黑色节点(D),情况较复杂,要根据父节点(P),兄弟节点(S),兄弟右子节点(SL),兄弟左子节点(RL)共同决定相应操作。
- P任意,S节点红:对树进行旋转,交换S,P颜色,然后转换成父节点红色问题。
- P任意,S黑,SR红 : 旋转,交换S,P颜色,SR颜色变黑。
- P任意,S黑,SL红: 右旋,转换成问题2
- P红,S黑:P变黑,S变红。
- P,S, SL, SR全黑:删除D,S变红,然后把P当做D从新节点是使用五种规则向上递归调整红黑树。