当前位置: 首页 > article >正文

【C/C++】红黑树插入/删除修复逻辑解析

文章目录

  • 红黑树插入修复逻辑解析
    • ✅ 函数原型
    • ✅ 外层循环条件
    • ✅ 拿到祖父节点
    • ✅ Case 1:父节点是祖父的左孩子
      • ① 叔叔节点是红色 → 情况1:**颜色翻转(Recolor)**
      • ② 叔叔节点是黑色或为空 → 情况2或3:**旋转 + 颜色修复**
    • ✅ Case 2:父节点是祖父的右孩子(对称处理)
      • ❗ 这个地方有个**严重 bug**:
      • 后续逻辑和 Case 1 是对称的:
    • ✅ 循环退出后,把根节点设为黑色
    • 完整代码示意(带图解)
    • ✅ 总结五大逻辑结构
  • 红黑树删除修复逻辑解析
    • 🔧 函数签名与入口判断
    • 🧩 Case 分支:`x` 是左子节点(`x == xParent->left`)
      • 📌 Case 1:`w`(兄弟)是红色
      • 📌 Case 2:`w` 是黑色,且左右孩子都黑(或空)
      • 📌 Case 3:`w` 是黑色,左是红,右是黑
      • 📌 Case 4:`w` 是黑色,右是红
    • 🔄 对称分支:`x == xParent->right`
    • ✅ 最终清理
    • 🧠 总结逻辑图(以 `x == xParent->left` 为例)

红黑树插入修复逻辑解析


✅ 函数原型

void InsertFixup(Node* &root, Node *node)
  • root 是红黑树的根节点的引用(可变)。

  • node 是刚插入的新节点。

  • 目标:让树重新满足红黑性质,特别是:

    • 不能有两个连续的红色节点(性质 4)
    • 根节点必须为黑色(性质 2)

✅ 外层循环条件

while (node != root && node->parent->color == RED)
  • 只在当前节点不是根、且父节点是红色时修复。
  • 父为红色违反了“红色节点的子节点必须是黑色”的红黑性质。

✅ 拿到祖父节点

Node *gp = node->parent->parent;
  • 因为父是红色,说明一定不是根节点 → 父节点有祖父节点。
  • 所以这里拿 gp 安全。

✅ Case 1:父节点是祖父的左孩子

if (node->parent == gp->left)

然后分成两种情况:

① 叔叔节点是红色 → 情况1:颜色翻转(Recolor)

Node *uncle = gp->right;
if (uncle != nullptr && uncle->color == RED) {node->parent->color = BLACK;uncle->color = BLACK;gp->color = RED;node = gp;
}
  • 父和叔都是红的,违反红黑规则。
  • 做法是将 父和叔变黑,祖父变红,然后将当前节点指向祖父继续上移修复。

② 叔叔节点是黑色或为空 → 情况2或3:旋转 + 颜色修复

else {if (node == node->parent->right) {node = node->parent;RotateLeft(root, node);}node->parent->color = BLACK;gp->color = RED;RotateRight(root, gp);
}
  • 如果当前是“右-左”情况(新节点是父的右子),先左旋变成“左-左”结构。
  • 然后右旋祖父,父变为子树新根。
  • 同时调整颜色,维持红黑规则。

✅ Case 2:父节点是祖父的右孩子(对称处理)

else {Node *uncle = gp->left;if (uncle->parent->color == RED) {

❗ 这个地方有个严重 bug

if (uncle->parent->color == RED)
  • 这里不应该访问 uncle->parent->color,应该是:

    if (uncle != nullptr && uncle->color == RED)
    
  • 否则当 uncle == nullptr 会导致空指针访问崩溃!

后续逻辑和 Case 1 是对称的:

node->parent->color = BLACK;
uncle->color = BLACK;
gp->color = RED;
node = gp;

或者:

if (node == node->parent->left) {node = node->parent;RotateRight(root, node);
}
node->parent->color = BLACK;
gp->color = RED;
RotateLeft(root, gp);

✅ 循环退出后,把根节点设为黑色

root->color = BLACK;
  • 保证红黑树“根节点是黑色”这一性质。

完整代码示意(带图解)

void InsertFixup(Node* node) {while (node != root && node->parent != nullptr && node->parent->color == RED) {Node* parent = node->parent;Node* grandparent = parent->parent;if (grandparent == nullptr) break;// Case: parent 是 grandparent 的左孩子if (parent == grandparent->left) {Node* uncle = grandparent->right;if (uncle != nullptr && uncle->color == RED) {/*** Case 1: 叔叔是红色,颜色翻转 + 上移**       gp(R)              gp(R) 变红后需要向上递归修复*      /     \     =>     /     \*   pa(R)   unc(R)      pa(B)   unc(B)*    /* node(R)*/parent->color = BLACK;uncle->color = BLACK;grandparent->color = RED;node = grandparent; // 向上传递修复责任} else {if (node == parent->right) {/*** Case 2: node 是“折弯”结构 —— 需要先转成直线**       gp(R)*      /*   pa(R)*      \*     node(R)** 先对 parent 左旋*/node = parent;RotateLeft(node);}/*** Case 3: node 是“直线”结构,右旋 grandparent**       gp(R)                 pa(B)*      /      =>             /    \*   pa(R)                  node(R) gp(R)*   /* node(R)*/node->parent->color = BLACK;   // parent 变为局部根,染黑grandparent->color = RED;RotateRight(grandparent);node = node->parent; // 当前的 parent 是新的局部根,继续修复}} else {// 对称情况:parent 是右孩子Node* uncle = grandparent->left;if (uncle != nullptr && uncle->color == RED) {/*** Case 1(对称): 叔叔是红色*/parent->color = BLACK;uncle->color = BLACK;grandparent->color = RED;node = grandparent;} else {if (node == parent->left) {/*** Case 2(对称): 折弯结构,先右旋 parent*/node = parent;RotateRight(node);}/*** Case 3(对称): 直线结构,左旋 grandparent*/node->parent->color = BLACK;grandparent->color = RED;RotateLeft(grandparent);node = node->parent;}}}// 最终确保根是黑色,满足性质 2root->color = BLACK;
}

✅ 总结五大逻辑结构

条件动作
父红,叔红父、叔设黑,祖父设红,往上递归
父红,叔黑,新节点在右左旋父
父红,叔黑,新节点在左父设黑,祖父设红,右旋祖父
对称情况(父为右子)与上面对称处理
根节点必须为黑色最后强制设 root 为黑

红黑树删除修复逻辑解析

🔧 函数签名与入口判断

void DeleteFixup(Node* &root, Node *x, Node *xParent)
  • x 是替代被删除节点的位置,可能是 nullptr。
  • xParentx 的父节点(尤其在 x == nullptr 时需要)。
  • root 是整棵树的引用。
while ((x == nullptr || x->color == BLACK) && x != root)

只要 x 是“多余的黑色”,且不是根,就继续修复。


🧩 Case 分支:x 是左子节点(x == xParent->left

📌 Case 1:w(兄弟)是红色

if (w->color == RED) {w->color = BLACK;xParent->color = RED;RotateLeft(root, xParent);w = xParent->right; // 更新兄弟
}

✅ 通过旋转将兄弟变成黑色,把 Case 1 转换为 Case 2/3/4。


📌 Case 2:w 是黑色,且左右孩子都黑(或空)

if ((w->left == nullptr || w->left->color == BLACK)&& (w->right == nullptr || w->right->color == BLACK)) {w->color = RED;x = xParent;xParent = xParent->parent;
}

✅ 兄弟无法提供黑色,继续向上修复。


📌 Case 3:w 是黑色,左是红,右是黑

if (w->right == nullptr || w->right->color == BLACK) {if (w->left != nullptr) {w->left->color = BLACK;}w->color = RED;RotateRight(root, w);w = xParent->right;
}

✅ 转换成 Case 4。


📌 Case 4:w 是黑色,右是红

w->color = xParent->color;
xParent->color = BLACK;
if (w->right) {w->right->color = BLACK;
}
RotateLeft(root, xParent);
x = root;

✅ 最终修复,黑高恢复,终止循环。


🔄 对称分支:x == xParent->right

代码完全对称,只是把“左”和“右”调换:

  • 兄弟变为 xParent->left
  • 旋转方向反过来:左旋 → 右旋,右旋 → 左旋
  • 子节点判断也对称。

✅ 最终清理

if (x != nullptr) {x->color = BLACK;
}

避免残留“多余黑色”。


🧠 总结逻辑图(以 x == xParent->left 为例)

Case条件操作说明
1w 是红调色+左旋 → 转为 2/3/4
2w 黑,左右孩子都黑兄弟设红,双黑上移
3w 黑,左红右黑调色 + 右旋兄弟 → 转为 Case 4
4w 黑,右红兄弟右设黑 + 父兄换色 + 左旋 → 修复完成
http://www.lryc.cn/news/2384517.html

相关文章:

  • RabbitMQ可靠传输——持久性、发送方确认
  • AWS stop/start 使实例存储lost + 注意点
  • 数字计数--数位dp
  • 掌握递归:编程中的优雅艺术
  • 无人机开启未来配送新篇章
  • el-input宽度自适应方法总结
  • Qt状态机QStateMachine
  • 驱动开发学习20250523
  • Java详解LeetCode 热题 100(20):LeetCode 48. 旋转图像(Rotate Image)详解
  • CAU人工智能class4 批次归一化
  • Android11以上通过adb复制文件到内置存储让文件管理器可见
  • Keepalived 与 LVS 集成及多实例配置详解
  • 篇章二 需求分析(一)
  • 汽车充电过程中--各个电压的关系(DeepSeek)
  • 图解深度学习 - 机器学习简史
  • Gmsh 代码深度解析与应用实例
  • 49页 @《人工智能生命体 新启点》中國龍 原创连载
  • 量化研究---bigquant策略交易api研究
  • 编译原理 期末速成
  • echarts之漏斗图
  • 零基础设计模式——第二部分:创建型模式 - 原型模式
  • Honeywell TK-PRS021 C200
  • java 进阶 1.0.3
  • 从 Docker 到 runC
  • PET,Prompt Tuning,P Tuning,Lora,Qlora 大模型微调的简介
  • 02-jenkins学习之旅-基础配置
  • 互联网大厂Java求职面试:云原生架构与AI应用集成解决方案
  • Python爬虫实战:研究Crawley 框架相关技术
  • C#实现List导出CSV:深入解析完整方案
  • Appium+python自动化(三)- SDK Manager