编辑
2025-04-12
记录知识
0
请注意,本文编写于 76 天前,最后修改于 59 天前,其中某些信息可能已经过时。

目录

必要条件
删除红色根节点
删除黑色根节点
删除只有一个节点的节点
删除节点的前驱节点是删除节点的左孩子
删除节点的前驱节点不是删除节点的左孩子
修复阶段:关注节点的兄弟节点是红色
修复阶段:关注节点作为右孩子时,其兄弟节点是黑色,右侄子是红色,左侄子是黑色
总结

本文根据<rb-tree实现-删除操作-原理>文章的原理描述,逐一演示删除操作

必要条件

  • 默认情况下,图示只按照前驱方式来寻找删除节点。
  • 默认情况下,图示先进行左旋/右旋然后再进行染色/颜色互换

删除红色根节点

红色根节点不影响平衡,无需调整,故直接删除,如下图

image.png

删除黑色根节点

假设当前红黑树如下,我们准备删除节点1

image.png

此时节点1有两个空黑节点,则直接进行第二阶段修复

在修复时,其情况为,兄弟节点6是黑色,且节点6包含两个空黑节点,如下图所示

image.png

于是步骤为如下:

  1. 将兄弟节点6染红
  2. 将父节点4染黑
  3. 将关注节点设置为节点4
  4. 向上递归

如下图示

image.png

此时对于节点4,其兄弟节点13是黑色,兄弟节点包含两个黑节点9和16,则步骤如下:

  1. 将兄弟节点13染红
  2. 将父节点8染黑
  3. 将关注节点设置为节点8
  4. 由于节点8是根节点,则调整完成

如下图示

image.png

删除只有一个节点的节点

假设当前红黑树如下,我们准备删除节点4

image.png

那么步骤如下

  1. 节点6替换节点4
  2. 将节点6染色为黑色

比较简单,就不截图了。

删除节点的前驱节点是删除节点的左孩子

要让删除节点的左孩子是删除节点的前驱节点,那么待删除节点的左孩子没有右孩子。 假设当前红黑树如下,我们准备删除节点8,因为节点8的左孩子节点4没有右孩子,所以节点4就是前驱节点

image.png

那么步骤如下:

  1. 将节点4替换到节点8上
  2. 将节点4的颜色设置为黑色
  3. 将节点4的左节点3设置为黑色

如下图

image.png

删除节点的前驱节点不是删除节点的左孩子

如果前驱节点不是删除节点的左孩子,那么前驱节点和被删除节点没有强相关性,我们在替换删除节点后,需要进行第二步根据实际情况修复步骤
假设当前红黑树如下

image.png

此时我们删除节点30,按照前驱方式,默认节点28作为替代节点,如下

image.png

此时替代节点是节点26的右孩子,其兄弟节点22是黑色,且其兄弟节点22有两个黑色节点,我们需要:

  1. 节点22强制染红色
  2. 然后将关注节点调整为父节点,也就是节点26

如下图

image.png

此时关注节点是26,其兄弟节点35是黑色,左侄子节点33是黑色,右侄子节点42是红色。我们需要:

  1. 左旋父节点,也就是节点28
  2. 左旋后,将祖父节点35设置为节点28的颜色,也就是红色
  3. 将父节点28设置为黑色
  4. 将叔叔节点42设置为黑色
  5. 调整完成

如下图

image.png

修复阶段:关注节点的兄弟节点是红色

为了复现此场景的例子,我们需要构造红黑树如下

image.png

此时我们删除节点28,此时节点27作为前驱节点替换到节点28位置上,而节点27作为关注节点,其兄弟节点21是红色。状态如下

image.png

此时步骤如下

  1. 将父节点26左旋
  2. 左旋完成后,将父节点26和祖父节点21颜色互换
  3. 继续检查关注节点

此时状态如下

image.png

此时关注节点的兄弟节点24是黑色,其左右孩子都是红色,符合场景:修复阶段:关注节点的兄弟节点是黑色,其左右侄子都是红色

此时关注节点作为节点26的右孩子,所以步骤如下

  1. 先右旋父节点26
  2. 将祖父节点24设置为父节点26的颜色(红色)
  3. 将父节点26设置为黑色
  4. 将叔叔节点23设置为黑色
  5. 调整结束

此时调整完成后的状态如下

image.png

修复阶段:关注节点作为右孩子时,其兄弟节点是黑色,右侄子是红色,左侄子是黑色

为了准备这种情况,我们需要构造红黑树情况如下,我们关注节点35,如下

image.png

此时我们删除节点35,那么节点33会替代节点35,然后关注节点在原节点33的位置,记住节点33是父节点32的右孩子,那么状态如下

image.png

此时关注节点的兄弟节点30是黑色,右侄子是红色,左侄子是黑色 我们需要目的将红色节点搬到左侄子节点上,那么步骤如下

  1. 兄弟节点30左旋
  2. 节点30和原右侄子节点颜色互换

那么此时状态如下

image.png

此时关注节点不变,其兄弟节点31是黑色,其左侄子节点是红色,右侄子节点是黑色,那么步骤如下

  1. 右旋父节点32
  2. 将祖父节点31的颜色设置为父节点32的颜色(红色)
  3. 将父节点32染黑
  4. 将叔叔节点30染黑
  5. 调整结束

上述步骤完成之后,状态如下

image.png

总结

至此,针对删除的所有场景演示完成了,本文没有按照关注节点的左右孩子都重复介绍,只是按照单边作为示例,演示了所有的场景。那么本文涉及到的场景如下:

可以对应文章<rb-tree实现-删除操作-原理>查看场景

删除阶段:

  1. 删除节点没有子节点
    章节: <删除红色根节点>
  2. 删除节点只有一个子节点
    章节: <删除只有一个节点的节点>
  3. 删除节点有两个子节点,前驱节点是其左孩子
    章节: <删除节点的前驱节点是删除节点的左孩子>
  4. 删除节点有两个子节点,前驱节点不是其左孩子
    章节: <删除节点的前驱节点不是删除节点的左孩子>

修复阶段:

  1. 兄弟节点是红色
    章节: <修复阶段:关注节点的兄弟节点是红色>
  2. 兄弟节点是黑色,且侄子都是黑色
    章节: <删除黑色根节点>
  3. 兄弟节点是黑色,其左侄子是红色,右侄子是黑色
    章节: <修复阶段:关注节点作为右孩子时,其兄弟节点是黑色,右侄子是红色,左侄子是黑色>(镜像)
  4. 兄弟节点是黑色,其左侄子是黑色,右侄子是红色
    章节: <删除节点的前驱节点不是删除节点的左孩子>
  5. 兄弟节点是黑色,其左右侄子都是红色
    章节: <修复阶段:关注节点的兄弟节点是红色>

至此,可以发现,全部演示完成。