(xa3)红黑树:插入

官方信息技术老师·16 页·深入(追求细节与边界)·0 次浏览·2 天前
红黑树插入修复树旋转数据结构

红黑树插入:修复的艺术

看清一次普通插入为何必定触发修复,掌握三种情形

按 空格/→ 演示下一步

1 / 16 页

全部页面点击任意一页,跳回舞台从这页播放

红黑树插入修复树旋转数据结构

红黑树插入:修复的艺术

看清一次普通插入为何必定触发修复,掌握三种情形

1第 1 页 · 红黑树插入:修复的艺术

什么是「以曲为直」

上页我们看到修复靠旋转,但旋转明明把节点位置换了,怎么反而让树变平衡?秘密就在「以曲为直」——看起来是绕远路的弯折,实际上是直达平衡的捷径。

弯在局部
旋转改三个指针,把过长路径折短一步
直在全局
红黑性质要求所有路径黑高一致
弯换直
几次旋转代价小,恢复平衡代价才大
折弯铁丝让两端对齐对应 →旋转让路径平衡

铁丝弯一下是为了让两端对齐;树旋转一下是为了让路径重新笔直

2第 2 页 · 什么是「以曲为直」

左旋 vs 右旋

左右旋像照镜子,但触发条件不同——分不清就会越修越歪。

左旋
  • 失衡方向:发生在祖父节点的右侧(RR 型 / RL 型修正后)
  • 操作动作:右子提为新根,原根降为左子
  • 本质:失衡节点的「右孙子」上位
右旋
  • 失衡方向:发生在祖父节点的左侧(LL 型 / LR 型修正后)
  • 操作动作:左子提为新根,原根降为右子
  • 本质:失衡节点的「左孙子」上位
失衡在祖父右侧时选左旋,在祖父左侧时选右旋——本质都是让「孙子」上位当父亲。
3第 3 页 · 左旋 vs 右旋

双红问题是什么

上一页讲了旋转能调整节点关系,但为何要旋?问题出在「染红」这一步。新节点默认染红,能避免破坏黑高。可万一父节点也是红色,父子撞色,红黑树就违规了——这就是双红问题。

染红的理由
新节点默认染红,可避免路径黑高变化、降低修复代价
双红的定义
插入后发现父节点也是红色,父子同红构成双红
违反的性质
性质4:红色节点的子节点必须为黑色,父子皆红直接冲突
为何必须修
BST 序未变但已不满足红黑约束,需要旋转或变色来修复
下级撞衫上级同穿红衣对应 →父子节点同红

父子层级同红违反「下级不能比上级更显眼」的潜规则,需要重新「调位置」

4第 4 页 · 双红问题是什么

双红缺陷的两种形态

从双红违规出发, 按 P 在 G 的左右分流成 RR-1 与 RR-2 两条镜像路径, 各自指向修复方向。

图解渲染中…
a1G 祖父, P 父节点, N 新插入节点, U 叔父c1RR-1: P 在 G 右侧, 路径 G→P→N 向右折角c2RR-2: P 在 G 左侧, 路径 G←P←N 向左折角f1两种形态互为镜像, 修复策略完全对称
5第 5 页 · 双红缺陷的两种形态

插入修复的宏观流程

插入后从下往上检查,遇到双红就按叔叔颜色选策略。

1
新节点染红插入
按 BST 规则插到叶子,染红以局部保持黑高
2
向上检查父色
沿父指针自底向上逐层检查父节点颜色
3
父黑直接结束
父为黑则无违规,红黑性质满足,停止修复
4
双红先看叔叔
父为红构成双红违规,必须判断叔叔颜色
5
按叔色分支处理
叔红走染色上推,叔黑走旋转+染色定型
6第 6 页 · 插入修复的宏观流程

修复策略的决策树

从插入红节点出发,先看父颜色;遇双红再看叔父,按分支选 RR-1 变色或 RR-2 旋转。

图解渲染中…
e1RR-1:父叔变黑、祖父变红,处理后可能向上递归h1RR-2:叔父为黑且插入点在外侧,对祖父旋转并换色i1内侧插入:先以父为支点旋转,把折线变直线再走 RR-2
7第 7 页 · 修复策略的决策树

RR-1 的处理策略

决策树把我们带到 RR-1:叔父节点也是红色。这是双红里最温和的一种——不旋转,只染色。但染色后祖父变红,可能在他那里再冒双红,所以我们还得把目光继续往上移。

触发条件
当前节点红、父节点红、叔父节点红
父与叔染黑
消除眼前两个红点,局部恢复
祖父染红
把双红风险向上传给上一代
向上回溯检查
以祖父为新起点,可能再触发修复
基层出了乱子往上汇报对应 →RR-1 染色修复

基层红点归位(染黑),异常上报上级(祖父染红),问题跟着上移

8第 8 页 · RR-1 的处理策略

RR-1 修复图解

看图理解 RR-1:叔叔为红时只做变色,不改变树结构,修复点上移。

图解渲染中…
B叔叔颜色是 RR-1 与 RR-2/3 的分水岭D3祖父变红可能在上层引发新的双红ERR-1 没有旋转,只改色F修复焦点从 N 移到祖父 G
9第 9 页 · RR-1 修复图解

RR-2 的处理策略

RR-1 叔叔是红色,简单换色就完事。RR-2 叔叔是黑色——麻烦来了:新节点和父亲可能扭成「三角」或「直线」两种别扭姿势。继续用「以曲为直」的思路:先掰直,再整体旋转。

形态判别
同方向为直线,反方向为三角
三角化直
对父亲做反向旋转,强行掰成直线型
旋转染色
对祖父旋转一次,原祖父变黑、上升者变红
拧成麻花的毛巾对应 →RR-2 先化曲为直再翻转

中间拧成麻花不能直接翻——先反向拧开拉直,再整体翻过去拧干

10第 10 页 · RR-2 的处理策略

RR-2 修复图解

三角→直线→旋转三步走,看 RR-2 如何从折线变直线再变平衡。

图解渲染中…
a1新 N 是父 P 的左子,父 P 又是祖父 G 的右子,呈折线a2左旋父后,N、P、G 落在同一直线(N、P 都在 G 左侧)a3右旋 + 变色:原 P 变黑居中,原 G 变红下沉,黑高恢复
11第 11 页 · RR-2 修复图解

RR-1 与 RR-2 对比

何时只需染色、何时必须旋转——插入修复的决策分水岭

RR-1:叔叔为红
  • 叔叔节点为红色
  • 仅需染色,不改树形
  • 违例上移到祖父层
RR-2:叔叔为黑
  • 叔叔为黑或不存在
  • 必须旋转,可能伴随染色
  • 本层即可解决
叔叔为红时只需染色;叔叔为黑(或为空)时必须旋转
12第 12 页 · RR-1 与 RR-2 对比

插入修复代码实现

cpp

RR-1 染色上提、RR-2 双旋整形——23 行 C++ 覆盖全部边界。

代码高亮加载中…

while 盯双红;RR-1 三方染色后 z 上提继续循环;RR-2 内侧先左旋整形,再'父黑祖红+右旋'定型;根强制黑保底。

13第 13 页 · 插入修复代码实现

自测检验

点击作答

红黑树插入修复双红缺陷时,下列哪种情况应采用「变色」处理(不旋转)?

14第 14 页 · 自测检验

本节要点回顾

  • 旋转换色是重画路径,不动插入点
  • 双红缺陷的本质是黑高被打破
  • RR-1 靠局部旋转换色,一步止损
  • RR-2 靠递推上溯,把冲突推给祖先
  • 叔叔颜色是唯一的决策信号
延伸主题:红黑树删除的修复2-3-4 树与红黑树的等价性AVL 树与红黑树的取舍
15第 15 页 · 本节要点回顾

课后思考

先自己琢磨三分钟,再对照参考答案看思路是否一致。

1RR-1 只需变色不旋转,为什么红黑树的性质依然能保住?

参考答案染色只改变局部颜色,祖父变红、父子变黑,从祖父往上看的子树黑高没变;但祖父变红可能向上触发新的双红,修复可能要循环到根。

2连续插入一组递增的键,红黑树大约会发生多少次旋转?比 AVL 树多还是少?

参考答案插入 n 个递增键,旋转次数是 O(log n) 量级,比 AVL 树少很多——AVL 要求严格平衡,红黑树容忍适度倾斜,换来更少的旋转代价。

3如果把「父节点为红」这个触发条件拿掉,RR-2 的旋转策略还站得住吗?

参考答案拿掉后 RR-2 处理需要重写:没有「父红」信号就定位不了失衡点;得另设触发规则,而且单次旋转可能不足以恢复所有不变量。

16第 16 页 · 课后思考