C++如何实现一个简单的红黑树(Red-Black Tree)删除节点算法

红黑树删除后易错乱或崩溃,因删除可能破坏全部5条性质,需通过delete_fixup修复双黑状态;核心是按case1~4顺序处理兄弟节点w及其侄子,严格判空并更新指针,替换后继时须拷贝颜色且保证nil哨兵参与比较。

c++如何实现一个简单的红黑树(red-black tree)删除节点算法

红黑树删除后为什么总是颜色错乱或指针崩溃?

因为删除比插入更复杂:它可能破坏红黑树的全部 5 条性质,尤其是「任意路径上黑节点数相等」和「不能有连续红节点」这两条。直接删掉一个节点后,往往要靠 fixup 过程来修复——而这个过程不是简单 recolor,经常需要旋转 + 多重 case 分支。很多人卡在 delete_fixup 的 case 3 和 case 4,本质是没理清「双黑」(double black)这个虚拟状态怎么传播和消解。

如何正确实现 delete_fixup 的核心逻辑?

delete_fixup 的输入是一个「疑似双黑」的节点(实际是 nullptr 或指向某个黑节点的指针),目标是让它变回单黑或红,同时保持整棵树平衡。关键在于:所有 case 都围绕 x 的兄弟节点 w 展开,且必须严格按顺序判断兄弟的颜色、侄子的颜色、以及旋转方向。

  • case 1:兄弟 w 是红色 → 先左/右旋让 w 变黑,父变红,再进 case 2–4
  • case 2:兄弟 w 黑,且两个侄子都黑 → 把 w 染红,x 上移(即设为 x->parent),继续循环
  • case 3:兄弟黑,近侄子红、远侄子黑 → 对近侄子旋转,再转成 case 4
  • case 4:兄弟黑,远侄子红 → 旋转 + recolor,之后直接退出循环

注意:case 3 和 case 4 中的「近/远」取决于 x 是左孩子还是右孩子,必须用 x == x->parent->left 判断,不能硬编码 left/right。

删除节点时怎么选后继才不破坏红黑性质?

标准做法是:若被删节点有两个孩子,用它的中序后继(右子树最左节点)替换;但后继**一定没有左孩子**(否则就不是最左),所以它最多只有一个右孩子。这意味着替换后,真正被删的节点最多只有一棵子树——这极大简化了后续 fixup:你只需要处理「删叶子」或「删只有一个孩子的节点」两种情形,不用考虑双子树合并。

立即学习“C++免费学习笔记(深入)”;

  • 如果后继是红色,直接替换并染黑父节点即可(不会引入双黑)
  • 如果后继是黑色,替换后它原来的位置会产生一个「黑缺失」,这就是 delete_fixup 的起点
  • 务必记得:替换时要拷贝颜色,而不是简单交换指针;否则颜色信息丢失

哪些细节会导致 segfault 或验证失败?

最常见的崩坏点不在算法主干,而在边界处理:

  • nullptr 节点不能访问 colorparent → 所有判空必须早于取字段,比如写 w && w->color == RED,而不是 w->color == RED
  • 哨兵节点(nil)必须全程参与比较:比如判断侄子是否黑,要写 w->right == nil || w->right->color == BLACK,不能只看非空指针的颜色
  • 旋转后必须更新 parent 指针,尤其当旋转涉及根节点时,漏改 root 会导致整个树脱钩
  • 删除后记得把 root->color = BLACK —— 即使 fixup 没走到根,也要兜底,因为根必须是黑的

真正难的不是写出 5 个 case,而是确保每个 case 里 parent/child 指针都双向一致,且 nil 节点始终作为叶子占位。稍有疏忽,validate 函数就会报「black-height mismatch」或「red-red violation」。

文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/jiquanzatan/124082.html

php7.4部署宝塔后网站打开速度慢如何优化
上一篇 2026-07-01 17:00
轻松搞定thinkphp使用与表单验证【安全篇】
下一篇 2026-07-01 17:13

相关推荐