红黑树(3) - 删除操做

在本系列的前面两篇文章中。已经介绍了红黑树以及其插入操做。

详细可參考如下两个连接:
红黑树(1) - 介绍
红黑树(2) - 插入操做
spa

1.删除操做介绍

相似于插入操做。红黑树进行删除节点时,也使用又一次着色以及旋转这两种方式。来维护它的属性。在插入操做中,咱们主要是依靠检測叔节点的颜色来决定哪一种场景。在删除操做中,咱们使用检測兄弟的颜色,来决定是哪一种场景。


在插入操做中,最多见的违反红黑树属性的一种状况是存在两个连续的红色节点。.net

而在删除操做中。常见的状况是,当删除节点是黑色时,会影响从根节点到叶子的黑色节点高度。违反红黑树的性质5。blog


删除的过程相对照较复杂。为了便于理解删除过程,咱们将使用到"double black"的概念。当一个黑色节点被删除,并且被它的黑色孩子代替时,这个孩子就标记为double black。所以,基本的工做就变为了将这个double black转换为single black。
ci

2.删除操做步骤

如下是具体的删除步骤。

在如下的内容里。d表示被删节点。c表示将用于替换d的孩子节点get

运行标准的二叉搜索树的删除操做。在删除过程当中,假设d是叶子或者仅仅有一个孩子。则操做比較简单,基本上直接删除就可以了。而对于存在两个孩子的节点,可以先查找到d的中序遍历时的后继节点。用它的值替换掉d的值,而后再删除这个后继节点(中序遍历时的兴许节点老是一个叶子或仅仅有一个孩子)。

例如如下图所看到的。这种话。咱们仅仅需要处理被删节点是叶子或仅仅有一个孩子的这种状况。class

              50                                            60                                        60
           /     \           delete(50)               /   \          delete(60')           /  \
        40     70    ----------------->      40    70 ------------------>   40   70
                 /  \      后继节点赋值                  /  \      删除后继节点               \
              60   80   给被删节点                  60'   80                                      80 
上图中,被删节点d是50,则它的中序遍历后继节点是60。用后继节点的值替换d的值,而后删除60这个后继节点。
固然,在本步骤中,也可以选取前驱节点(即被删节点左子树最大值)进行替换。

原理与后继节点类似。这里再也不描写叙述。原理

3. 简单场景-d或者c是红色

使用孩子节点c替换d。而后将其置为黑色。这样黑色高度维持不变。这是因为d和c不可能同一时候是红色。当中必然有一个为黑色。
本步骤会覆盖到如下的这4种场景。

              30                            30
           /     \       delete(20)        /   \
          20      40    ------------->    10    40 
         /                                  
        10                          
              30                            30
           /     \       delete(10)        /   \
          10      40    ------------->    20    40 
            \                               
            20         
              30                            30
           /     \       delete(20)        /   \
          20      40    ------------->    10    40 
         /                                  
        10        
              30                            30
           /     \       delete(10)        /   \
          10      40    ------------->    20    40 
            \                                  
            20  
对于d拥有两个孩子(两颗子树)的场景。如如下的两个图所看到的。可以採用第2节提供的方法。转换为处理叶子节点或单个孩子的场景。
              40                                 40                                40
           /     \        delete(20)           /   \        delete(30')           /  \
          20      50 ---------------------->  30    50 --------------------->   30   50
         /  \          运行步骤2.1,将d的       /  \      此时转换为了删除叶子30'.   /
        10  30         后继节点的值赋给d.      10  30'                           10
              40                                 40                                40
           /     \        delete(20)           /   \        delete(30')           /  \
          20      50 ---------------------->  30    50 --------------------->   30   50
         /  \          运行步骤2.1,将d的       /  \      此时转换为了删除叶子30'.   /
        10  30         后继节点的值赋给d.      10  30'                           10

4. 复杂场景-d和c都是黑色(包含d是叶子)

4.1. 孩子节点c是double black

此时,主要工做就是将这个double black转换为single black。注意:当d是叶子时,则默认c为null节点并且为黑色。

因此,假设删除的是黑色叶子,则也会引起double black操做。二叉树


上图中,在转换为了double black后,实际上已经变成了4.2.1.c的场景。可以使用Right Right Case旋转方式。
终于,删除节点20后,这棵树调整为:
              30                            40
           /     \       delete(20)        /   \
          20      40    ------------->    30    50 
                    \                             
                     50               

4.2. d是double black。或者d不是根节点

在这样的状况下,若是s表示d的兄弟节点,则存在如下这些场景。

4.2.1. s是黑色,并且s的孩子中至少有一个是红色。则进行旋转

若是s的这个红色的孩子为r,则依据s和r的位置,可以分为4种状况。

a. Left Left Case (s是左孩子,且r是s的左孩子或者s的两个孩子都是红色)。搜索

这样的情形与如下的Right Right Case正好相反。遍历

b. Left Right Case (s是左孩子,且r是s的右孩子)。这样的情形与如下的Right Left Case正好相反。

c. Right Right Case (s是右孩子,且r是s的右孩子或者s的两个孩子都是红色)。


d. Right Left Case (s是右孩子,且r是s的左孩子)。



4.2.2. s是黑色,并且s的两个孩子都是黑色(包含s是叶子)

这样的状况下需要又一次着色。并且:
a. 假设s的父节点是黑色,则作完删除操做后,还需要检測父节点。


b. 假设s的父节点是红色,则不需要再检測父节点,而是可以简单地将其设置为黑色(红色+double black = single black)。

4.2.3. s是红色,运行旋转操做,提高s。并且又一次着色s以及它的父节点

此时新的兄弟节点老是黑色的(下图的节点25)。至此,已经将这棵树经过旋转,转换为了兄弟为黑色的这样的场景。使用4.2.1或者4.2.2继续处理。这样的情形可以分为两种状况。
a. Left Case (s是左孩子)。右旋转父节点p。
b. Right Case (s是右孩子). 左旋转父节点p。



4.3. 假设c是根节点,将其转换为single black而后返回(全然二叉树的黑色高度减1).

相关文章
相关标签/搜索