跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

C++ 实现红黑树节点的变色与平衡调整策略之六种插入情形深度剖析与实现【源码】

插入新节点必染红,仅可能违反“红节点不能连续”规则;修复时以祖父为单位,根据叔叔颜色与节点位置组合,严格穷举出六种情形,本质是LL/RR/LR/RL四种结构在红黑约束下的颜色+旋转完整覆盖。 红黑树插入后不直接调用
rotate
或
recolor
就想平衡?大概率会漏掉祖父节点颜色状态、uncle 节点存在性判断,或误判当前节点在父节点左右子树中的相对位置——这六种情形本质是三种结构模式(LL/RR/LR/RL)在红黑性质约束下的颜色+旋转组合展开,不是独立 case。 为什么插入只产生六种情形,而不是更多? 插入新节点后,红黑树仅违反「红节点不能有红子节点」这一条(新节点染红,父节点若为红则冲突)。修复必须从冲突点向上追溯至祖父节点(grandparent),而 uncle 节点(父节点的兄弟)的颜色决定处理路径: uncle 为红 → 只需变色:
parent
和
uncle
染黑,
grandparent
染红,再以
grandparent
为新冲突点继续向上处理 uncle 为黑(或 nullptr)→ 必须旋转:此时需根据
node
相对于
parent
、
parent
相对于
grandparent
的左右位置,归类为 LL / RR / LR / RL 四种形态;但 LR 和 RL 各含两种颜色配置(
grandparent
红/黑),合起来共六种可穷举的情形 所谓“六种”,是
uncle == nullptr
时,对四种旋转形态 × 两种祖父颜色的完整覆盖,不是随意编号。
insert_fixup
中如何正确识别当前属于哪一情形? 关键不是数“第几种”,而是分步判断: 立即学习 “ C++免费学习笔记(深入) ”; C知道 CSDN推出的一款AI技术问答工具 下载 先确认
node != root && node->color == RED && node->parent->color == RED
再获取
grandparent = node->parent->parent
,并检查
grandparent
是否存在(否则已到根,结束) 用
node == node->parent->left
和
node->parent == grandparent->left
组合判断方向,避免硬编码 left/right 字符串匹配 最后查
uncle
:若
parent
是
grandparent
左子,则
uncle = grandparent->right
;反之亦然。再判
uncle && uncle->color == RED
漏掉
uncle == nullptr
的分支,或把
uncle
为空当成“黑”来统一处理,会导致 LL/RR 情形被错误归入变色逻辑,后续必崩。 旋转与变色顺序为什么不能颠倒? 所有旋转操作(
left_rotate
/
right_rotate
)都假设子树满足 BST 结构,且旋转后需立即修正三节点颜色,否则中间态必然违反红黑性质: LL 型(node 是 parent 左、parent 是 grandparent 左):必须先
right_rotate(grandparent)
,再将原
parent
染黑、原
grandparent
染红 —— 若先变色,
parent
变黑后,其右子(原 grandparent)仍连着一个红子,BST 层级未改但颜色已错 LR 型:必须先
left_rotate(parent)
把 node 提到 parent 位,再
right_rotate(grandparent)
,最后统一设色。跳过第一次旋转,直接对 grandparent 右旋,会破坏 BST 中序关系 任何情形下,旋转后若不立刻重设三节点颜色(新 parent 黑,两个子红),都会导致连续红节点或黑高不等 常见错误是把“变色”写成独立函数提前调用,或在旋转后忘记更新
node->parent->color
,结果调试时发现树看似平衡了,但
verify_rbtree()
一跑就报「black-height mismatch」。 真正难的不是写出六种 if-else 分支,而是确保每次旋转后,参与旋转的三个节点(new_parent, old_parent, child)颜色重置逻辑与当前路径上
grandparent
的原始颜色严格对应——这个细节没有注释很容易被忽略,但一旦出错,问题会延迟到后续插入或删除时才暴露。

相关文章