[TOC]
红黑树插入思路
好的,我们把 红黑树插入的完整逻辑整理一下,分步骤、分情况讲,保证清晰易懂:
🔹 红黑树插入逻辑
1️⃣ 基本步骤
-
普通 BST 插入
- 按二叉搜索树的规则,把新节点
x
插入到合适位置。 - 新节点初始化为 红色(因为插入红色节点更容易维持黑高)。
- 按二叉搜索树的规则,把新节点
-
判断是否需要修复
插入新节点 z (红色)
|
+-- 父是黑色 → OK,直接插入
|
+-- 父是红色
|
+-- 叔叔是红色 → 父黑叔黑,祖红,上移到祖父,继续检查
|
+-- 叔叔是黑色
|
+-- z 在父的同向(左左或右右) → Case 3,旋转 + 颜色交换
+-- z 在父的异向(左右或右左) → Case 2,先旋转父,再变为同向,继续 Case 3
- 如果父节点是黑色 → 红黑性质不破坏,不需要 fix。
- 如果父节点是红色 → 违反“红色节点不能有红色子节点”,需要修复。
- 考虑叔叔是不是红的
- ->叔叔是红的就 一起变黑,祖父变红
- ->叔叔不是红的,考虑旋转+变色
2️⃣ fixinsert 修复逻辑
设:
x
= 当前插入节点p
= 父节点u
= 叔叔节点(父节点的兄弟)g
= 祖父节点
情况 1:叔叔节点是红色
-
条件:
p
是红色,u
是红色 -
处理:
- 父节点
p
染黑 - 叔叔节点
u
染黑 - 祖父节点
g
染红 - 将
x
上移到祖父节点g
,继续循环判断
- 父节点
-
原因:通过重新染色,把红红冲突上移,保持黑高不变
情况 2:叔叔节点是黑色
- 条件:
p
是红色,u
是黑色 - 子情况(根据
x
在父节点的左右位置):
-
左-左(LL)
-
x
是p
的左孩子,p
是g
的左孩子 -
处理:
- 父节点染黑,祖父染红
- 右旋祖父
-
-
左-右(LR)
-
x
是p
的右孩子,p
是g
的左孩子 -
处理:
- 左旋父节点(将 LR 转化为 LL)
- 再执行 LL 情况的右旋 + 染色
-
-
右-右(RR)
- 对称 LL:右孩子的右孩子插入
- 左旋祖父 + 调整颜色
-
右-左(RL)
- 对称 LR:右孩子的左孩子插入
- 右旋父节点 → 变成 RR → 左旋祖父 + 调整颜色
3️⃣ 循环终止
- 当父节点是黑色,或者到达根节点,循环结束
- 最后 根节点必须染黑
🔹 总结关键点
-
新节点红色 → 保持黑高不变
-
红红冲突 → 根据叔叔颜色分两类处理:
- 红色叔叔 → 上移染色
- 黑色叔叔 → 旋转 + 染色
-
旋转 + 染色 → 只改变局部结构,保持整体 BST 和红黑性质
-
根节点保持黑色 → 保证树的黑高一致
如果你需要,我可以帮你画一张 红黑树插入示意图,把 LL/LR/RR/RL 四种旋转场景和颜色变化可视化,看起来非常直观。
你想让我画吗?
红黑树删除思路
好,我给你梳理一下 红黑树删除的整体思路,只讲逻辑,不贴代码:
1️⃣ 找到要删除的节点
- 首先按照普通二叉搜索树(BST)查找待删除节点
z
。 - 如果节点不存在,就结束。
2️⃣ 分情况处理节点
红黑树删除跟 BST 删除类似,分三种情况:
-
节点没有子节点(叶子)
- 直接把它从父节点断开。
- 如果节点是黑色,删除会破坏黑高,需要修复。
-
节点只有一个孩子
- 用唯一的孩子替代该节点挂到父节点上。
- 如果删除的是黑色节点,也可能破坏红黑性质,需要修复。
-
节点有两个孩子
- 找该节点的 中序后继(右子树最左的节点)替代它。
- 删除后继节点(后继最多有一个右孩子),这一步退化为情况 1 或 2。
- 然后把被删除节点的左右孩子接到后继上,继承颜色。
- 如果后继原本是黑色,也需要修复。
3️⃣ 修复红黑树性质
-
删除黑色节点或用黑色节点替代时,会破坏 黑高 或 红黑性质。
-
修复核心思路:
- 兄弟节点红色 → 旋转并调整颜色,使兄弟变黑。
- 兄弟黑色,兄弟的孩子都是黑色 → 兄弟染红,把“双重黑”向上传递。
- 兄弟黑色,有红色侄子 → 旋转 + 染色,直接消除双重黑。
-
修复循环一直执行,直到双重黑消除或者到达根节点。
4️⃣ 特别注意
- 根节点始终要保持黑色。
- 删除过程尽量使用 哨兵节点
nul
替代空指针,避免每次判断nullptr
。 - 删除逻辑主要是 BST 替换 + fixdelete 修复 两步结合。
简单总结一句话就是:
“先按 BST 删除节点,再根据被删节点颜色决定是否修复,用旋转和染色处理双重黑。”
好,我们把 红黑树删除后修复的核心步骤细化讲解一下,把每种情况的逻辑和原因都拆开看。假设删除后出现的节点 x
带有 “双重黑”(double black),这是修复的触发条件。
🔹 修复红黑树性质(Double Black 处理)
情景概念
- 删除或替代节点是黑色 → 破坏了红黑树的黑高。
- 我们用
x
表示替代节点(可能是哨兵nul
)。 w
表示x
的兄弟节点。
情况 1:兄弟节点红色
条件:w->color == RED
处理逻辑:
- 把兄弟染黑,父节点染红。
- 对父节点做旋转(左旋或右旋,视 x 在左还是右)。
- 转换成“兄弟是黑色”的情况,进入下一轮循环处理。
原因:
- 红色兄弟意味着父节点必然是黑色(红黑性质),旋转后可以让黑高平衡,同时把问题转化为更容易处理的兄弟黑色情况。
情况 2:兄弟是黑色且兄弟两个孩子都是黑色
条件:w->color == BLACK && w->left->color == BLACK && w->right->color == BLACK
处理逻辑:
- 把兄弟染红。
- 把 x 的双重黑向父节点传递:
x = x->parent
,循环继续。
原因:
- 黑高减少发生在 x 所在的路径上。
- 兄弟的两个子节点都是黑色 → 黑高没法补偿,只能把多余的黑色“向上递归”。
情况 3:兄弟是黑色且有红色侄子
条件:w->color == BLACK
且至少有一个子节点红色
处理逻辑:
-
如果 x 是左孩子:
- case RL:先对兄弟右旋,让红色侄子转到右侧。
- case RR:父亲左旋,同时调整父亲、兄弟和红色侄子的颜色。
-
对称地,如果 x 是右孩子:
- case LR:先左旋兄弟
- case LL:父亲右旋 + 染色
原因:
- 红色侄子可以“补偿”被删除黑色节点造成的黑高缺失。
- 通过旋转和染色,双重黑立即消除,红黑树性质恢复。
🔹 循环结束条件
- 双重黑消除(x 被重新染黑或者到达根节点)。
- 根节点必须保持黑色 → 最后再显式设置
root->color = BLACK
。
💡 直观理解:
- 红兄弟 → 转化问题
- 黑兄弟+黑侄子 → 往上递
- 黑兄弟+红侄子 → 补偿黑高,立即解决
如果你想,我可以画一张 删除修复流程图,用节点颜色标注每一步的旋转和染色,直观展示三种情况。
你希望我画吗?
没错 ✅,你总结得非常到位。
这是二叉搜索树(BST)删除的基本套路,红黑树只是额外多了颜色和修复步骤而已。
普通 BST 的删除分类
假设删除的节点是 z
:
-
没有孩子(叶子) → 直接删。
-
只有一个孩子 → 用孩子替换它。
-
有两个孩子 → 找 中序后继(右子树最小) 或 中序前驱(左子树最大),
- 把
y.key
复制到z.key
; - 实际删除
y
(而y
一定是“最多一个孩子”的情况)。
- 把
所以 情况 3 总是能转化为情况 1 或 2。
为什么后继/前驱最多只有一个孩子?
比如用 后继(右子树最小的节点)来说明:
y
在z.right
里,且y
是最靠左的。- 所以
y
不可能有左孩子(否则就不是最左的了)。 - 因此
y
要么没有孩子,要么只有右孩子。
对称地,用前驱的话,也必然是“没有孩子或只有左孩子”。
到红黑树这里
红黑树继承了 BST 结构,所以删除逻辑一样:
- 如果
z
有两个孩子,我们实际删的就是它的后继/前驱y
,而不是直接删z
。 - 这就是你说的“删除下移”。
真正复杂的地方在于:如果被删的是黑色节点,就需要一整套 fixup
来维持红黑树的平衡。
要不要我帮你把“3 种情况 → 转化为 2 种简单情况”的流程画成一个 决策图(删除流程图)?这样会更直观。