红黑树(3) - 删除操作

原创 2015年07月11日 22:30:29
在本系列的前面两篇文章中,已经介绍了红黑树以及其插入操作。具体可参考下面两个链接:
红黑树(1) - 介绍
红黑树(2) - 插入操作

1.删除操作介绍

类似于插入操作,红黑树进行删除节点时,也使用重新着色以及旋转这两种方式,来维护它的属性。在插入操作中,我们主要是依靠检测叔节点的颜色来决定哪种场景。在删除操作中,我们使用检测兄弟的颜色,来决定是哪种场景。
在插入操作中,最常见的违反红黑树属性的一种情况是存在两个连续的红色节点。而在删除操作中,常见的情况是,当删除节点是黑色时,会影响从根节点到叶子的黑色节点高度。违反红黑树的性质5。
删除的过程相对比较复杂。为了便于理解删除过程,我们将使用到"double black"的概念。当一个黑色节点被删除,并且被它的黑色孩子取代时,这个孩子就标记为double black。因此,主要的工作就变为了将这个double black转换为single black。

2.删除操作步骤

下面是详细的删除步骤。在以下的内容里,d表示被删节点,c表示将用于替换d的孩子节点
执行标准的二叉搜索树的删除操作。在删除过程中,如果d是叶子或者只有一个孩子,则操作比较简单,基本上直接删除就可以了。而对于存在两个孩子的节点,可以先查找到d的中序遍历时的后继节点,用它的值替换掉d的值,然后再删除这个后继节点(中序遍历时的后续节点总是一个叶子或只有一个孩子)。如下图所示。这样的话,我们只需要处理被删节点是叶子或只有一个孩子的这种情况。
              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).

红黑树的基本插入和删除操作

红黑树是一种二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是RED或者BLACK,通过对任何一条从根到叶子的简单路径上各个结点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出2...
  • Mr_Avin
  • Mr_Avin
  • 2017年02月02日 17:12
  • 355

红黑树删除操作

红黑树删除操作: 红黑树要删除某个key值时,首先还是要查找该key值在树中的位置,查找方法和搜索二叉树方法相同. 要删除的结点分为两种情况: 1.有左右两个孩子都存在.两个孩子都存在时,在该节点的右...

数据结构之红黑树(三)——删除操作

删除一个节点同样有可能改变树的平衡性,而且,删除所造成的不平衡性比插入所造成的平衡性的修正更加复杂。 化繁为简是算法分析中一个常用的方法。下面我们将欲删除节点分为三大类:欲删除节点为叶子节点、欲删除节...

红黑树之删除操作

转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7760584       算法导论书上给出的红黑树的性质如下,跟STL源...

浅谈红黑树的添加删除操作

红黑树的性质(牢记) 1、每个结点的颜色只能是红色或黑色。 2、根结点必须是黑色的。 3、每个叶子结点都带有两个空的黑色结点(被称为黑哨兵null),如果一个结点n的只有一个左孩子,那么n的右孩...

红黑树(删除操作)

上一篇文章主要讲到了红黑树的基本性质以及插入节点的操作,有了上面的基础后,今天就把红黑树剩余的一个难点也就是删除节点的操作详细的讲一下。 红黑树节点的删除方法一开始的操作和二叉搜索树差不多,都是首先...

C++ 红黑树增加、删除等操作

#include #include using namespace std; class RBNode{ public: int color; //0为红色,1为黑...

红黑书(三)红黑树的删除操作

c++完整代码(带插入、删除、查找等): #include using namespace std; #include //颜色枚举; enum _color { _None, _R...

【数据结构】树(三):红黑树插入与删除操作(C++实现)

红黑树性质及操作分析,包含C++代码实现
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:红黑树(3) - 删除操作
举报原因:
原因补充:

(最多只允许输入30个字)