我们在之前的文章中讨论了关于红黑树的以下主题。我们强烈建议将以下帖子作为本文的先决条件。
插入与删除:
与插入一样,重新着色和旋转用于维护红黑颜色属性。
在插入操作中,我们检查叔父节点的颜色来决定接下来的操作。在删除操作中,我们检查兄弟节点的颜色来决定合适的操作。
插入操作中不可违反的主要属性是不可以出现两个连续的红色。在删除中,不可违反的属性是:子树中的黑色高度,因为删除黑色节点可能会导致一个根到叶路径中的黑色高度降低。
删除是一个相当复杂的过程。为了更好地理解删除,我们需要使用了、双黑的概念。当黑色节点被删除并替换为黑色子节点时,该子节点被标记为双黑(double black)。现在的主要任务是将这种双黑转换为单黑。
删除步骤
以下是删除的详细步骤:
1)执行标准 BST 删除. 当我们在 BST 中执行标准删除操作时(递归删除),最终我们总会删除一个节点,它是一个叶子节点或只有一个子节点(对于内部节点,我们复制后继节点,然后递归调用后继节点的删除,后继节点始终是叶节点或一个有一个子节点的节点)。所以我们只需要处理叶节点或有一个子节点的内部节点的情况。设 v 为要删除的节点,u 为替换 v 的子节点(注意,当 v 为叶叶节点且 NULL 的颜色被视为黑色时,u 为 NULL)。
2)简单案例:如果 u 或 v 是红色的,我们将替换的节点标记为黑色(黑色高度没有变化)。请注意,u 和 v 都不能是红色的,因为 v 是 u 的父级,并且红黑树中不允许出现两个连续的红色。
3) 如果 u 和 v 都是黑色
3.1) 将 u 标记为双黑。现在我们的任务减少到将这个双黑转换为单黑。请注意,如果 v 是叶子,那么 u 是 NULL,并且 NULL 的颜色被认为是黑色。所以删除黑叶也会导致双黑。
3.2)在当前节点 u 为双黑且不是根节点时,令该节点的兄弟节点为s。
(a):如果兄弟节点s 是黑色并且s的子节点至少一个是红色,则执行旋转。让 s 的红色子节点成为r。根据 s 和 r 的位置,这种情况可以分为四个子情况。
- 左左(s 是其父的左子,r 是 s 的左子,或者 s 的两个子节点都是红色的)。这是下图中显示的右右案列的镜像。
- 左右(s 是其父节点的左子节点,r 是右子节点)。这是下图所示的右左案列的镜像。
- 右右(s 是其父节点的右子节点,r 是 s 的右子,或者 s 的两个子节点都是红色的)
- 右左(s 是其父节点的右子节点,r 是 s 的左子节点)
(b):如果s是黑色并且它的两个孩子都是黑色,则直接重新着色,如果父级是黑色,则重复之前操作。
在这种情况下,如果父级是红色的,那么我们就不需要重复,我们可以直接将其设为黑色(红色 + 双黑色 = 单黑色)
(c): 如果兄弟节点是红色,则执行旋转向上移动旧的兄弟节点,重新着色旧的兄弟节点和父节点。新的兄弟将会是黑色的(见下图)。这样做的目的是将树的结构通过旋转转化为我们上面讨论过的情况(a)或(b)。这种情况有以下两个子情况。
- 左子(s 是其父级的左子级)。我们向右旋转父 p。
- 右子(s 是其父母的右子级)。我们左旋转父级 p。
3.3)如果 u 是根节点,则将其设为单一黑色并返回(完整树的黑色高度减 1)。
相关文章:
完整示例代码下载链接:
(包含各种语言:C语言、Python、Java,C++等均有示例)
免费资源下载:嗅探网(点击下载)