Article

算法导论-CH13-红黑树

算法导论-CH13-红黑树,待补充摘要。

May 23, 2026 修考 16 min read

Demo: Balancing with Tree Rotation

红黑树demo

CS61B Lecture 19 课程笔记:树旋转与红黑树 (Tree Rotations & LLRBs)

知识脑图与手写笔记逻辑结构

本篇笔记结合了课堂课件与手写笔记的精华,按照以下核心逻辑顺序展开:

  1. 研究动机 (Motivation):为什么不用 2-32\text{-}3 树?(实现极其痛苦)
  2. 树旋转 (Tree Rotation):如何通过旋转(rotateLeft / rotateRight)在不破坏 BST 性质的前提下改变树的高度与结构?
  3. 左倾红黑树 (LLRB):通过引入 “红链接 (Red Glue)” 将 2-32\text{-}3 树完美投影(Isometry)到 BST。
  4. 动态平衡维护 (Maintaining Isometry):手写笔记核心——插入 4 步法则以及如何通过旋转与颜色翻转(Color Flip)自动保持树的平衡。
  5. 经典例题与演练:保留全部课堂互动与练习,并给出详细的推导步骤。

一、 研究动机:B-Trees 的痛点

在学习了 2-32\text{-}3 树和 2-42\text{-}4 树(即 B-Trees)后,我们知道它们能够保证完美的对数级查找时间 O(logN)O(\log N)。然而,高德纳(Donald Knuth)曾说过:

“Beautiful algorithms are, unfortunately, not always the most useful.” (美丽的算法遗憾地并不总是最实用的。)

在实际开发中直接实现 2-32\text{-}3 树会遇到以下严重痛点:

  • 多种节点类型难以维护:需要分别处理 2-Nodes 和 3-Nodes。
  • 节点类型相互转换极其繁琐:在插入和删除时,需要频繁在 2-Nodes、3-Nodes 和临时 4-Nodes 之间变换。
  • 向上回溯分裂(Split)逻辑复杂:需要沿着父节点指针一路向上回溯分裂并重新分配子节点。

替代思路 (Alternate Idea)

我们能否继续使用简单、统一的二叉搜索树 (BST) 结构,但通过某种机制让它自动保持平衡? 答案是:通过“树旋转 (Tree Rotation)”机制来调节高度。

二、 树旋转 (Tree Rotation)

1. 旋转的定义与标准操作程序 (SOP)

旋转操作能够在完全保留 BST 查找性质(即左小右大)的前提下,改变树的局部高度与局部根节点。

(1) 左旋 rotateLeft(G)

手写笔记 SOP 还原与完善

  1. xxGG 的右孩子。xx 将取代 GG 成为该子树的新根(New Boss)。
  2. GG 下沉,成为 xx 的左孩子(因为 G<xG < x)。
  3. xx 原本的左孩子(介于 GGxx 之间)转移,成为 GG 的新右孩子

直观图示

     G (旧根)                    x (新根)
    / \                        / \
   A   x                      G   C
      / \                    / \
     B   C                  A   B
  • 性质不变性验证
    • 旋转前:A<G<B<x<CA < G < B < x < C
    • 旋转后:A<G<B<x<CA < G < B < x < C(BST 顺序完美保留!)

(2) 右旋 rotateRight(P)

手写笔记 SOP 还原与完善

  1. xxPP 的左孩子。xx 将取代 PP 成为该子树的新根。
  2. PP 下沉,成为 xx 的右孩子(因为 P>xP > x)。
  3. xx 原本的右孩子(介于 xxPP 之间)转移,成为 PP 的新左孩子

直观图示

        P (旧根)                 x (新根)
       / \                     / \
      x   C                   A   P
     / \                         / \
    A   B                       B   C

2. 旋转的局限性与非法操作

  • 旋转不是万能的:如果某个节点没有相应的孩子,则无法向该方向旋转。
    • 例如:若节点 11 没有左孩子,执行 rotateRight(1)非法操作 (Invalid Operation)
  • 旋转的代价:通过树旋转,我们可以在 O(1)O(1) 的时间内改变树的高度。通过在整棵树上做最多 O(N)O(N) 次旋转,我们可以将任意形状的 BST 调整到平衡状态,但盲目尝试旋转开销太大。

三、 左倾红黑树 (Left-Leaning Red-Black Trees, LLRB)

1. 红链接的本质:2-3 树的同构映射 (Isometry)

为了知道“何时、何地进行旋转”,我们引入一个天才的想法:建立 BST 与 2-32\text{-}3 树的 1-对-1 投影关系

  • 2-Node 的映射:直接对应 BST 中的普通节点(黑链接)。
  • 3-Node 的映射2-32\text{-}3 树中的 3-Node 含有两个元素(较小值 LL,较大值 RR)。我们将其拆分为两个二叉节点,并用一条红色的“粘合线 (Glue Link)”*将* LL *作为* RR *的*左孩子相连。

手写笔记要点: 将 2-32\text{-}3 树使用一种 “glue” 来联系,用红线表示。这种红线说明连接的两个 item 实际上在 2-32\text{-}3 树中是在一起(属于同一个节点)*的。为了规范化,我们规定红链接*必须向左倾斜,即左倾红黑树(LLRB)。

3-Node 映射对照图

  2-3 Tree 里的 3-Node:          LLRB 里的表示:
      [ d   f ]                      f (Black)
     /   |   \                     / \
    b    e    g                (Red) d    g
                              / \
                             b   e

2. LLRB 的核心性质 (Properties)

基于 2-32\text{-}3 树的完美平衡性,LLRB 继承了以下极强的数学性质:

  1. 没有任意节点可以拥有两条红链接
    • 对应 2-32\text{-}3 树中最多只能有 3-Node(即 1 条红链接),不能出现 4-Node。
  2. 完美黑色平衡 (Perfect Black Balance)
    • 从根节点(Root)到任意叶子节点的空链接(Null Link)的路径上,黑色链接的数量必须完全相同。这是因为 2-32\text{-}3 树本身是完美平衡的,红链接只是内部的“粘合剂”,不增加 2-32\text{-}3 树的高度。
  3. 红链接只能是左倾的(这是 LLRB 特有的简化规定,标准红黑树允许右倾红链接)。

3. LLRB 树高分析 (Height Analysis)

手写笔记推导纠错与完善

  • 2-32\text{-}3 树的高度为 HH

  • 最矮路径:全由黑色链接组成(即一路上全都是 2-Nodes),高度为 HH

  • 极高路径(最长路径):红黑交替的路线(即一路上全都是 3-Nodes)。

    • 因为不能有两个连续的左倾红链接(每一层最多一个红链接),所以最长路径最多包含 HH 条黑链接和 H+1H+1 条红链接。

    • 因此,LLRB 的最大高度为:

      Heightmax2H+1Height_{max} \le 2H + 1

  • 由于 H=Θ(logN)H = \Theta(\log N),所以 LLRB 的高度也严格被控制在 Θ(logN)\Theta(\log N) 内。查找操作的运行时间最坏情况下也仅为 O(logN)O(\log N)

四、 维护同构映射:LLRB 的插入与旋转算法

📝 这里是手写笔记第二页的精髓! > 课件中的复杂情况被精简为了极其好记的 “4步法则 / SOP 维护机制”。当我们在树中插入新元素时,只需自底向上递归应用这四条规则,就能自动修复所有冲突。

🚨 LLRB 插入 4 步法则 (SOP)

① 规则一:新插入的元素,一律用 “Red Glue” 连接

  • 原理:在 2-32\text{-}3 树中,新元素总是先放入叶子节点中进行合并(即放入现有的节点中,而不是新开一层)。在二叉树中,这等价于用红链接(Glue)将新节点连接到父节点上。

② 规则二:如果是右侧 red glue \rightarrow rotateLeft

  • 原理:红链接必须左倾。如果插入到了右侧,需要通过一次左旋,将其转为合法的左倾红链接。
  • 图示
    Parent                     Parent
      \                          /
       New (Red)   ==旋===>    New (Red)

③ 规则三:如果有连续两个左侧 red \rightarrow rotateRight

  • 原理:不能出现连续两个左侧红链接(这在 2-32\text{-}3 树中代表一个非法的 4-Node,且偏向一侧严重失衡)。通过右旋,我们可以将结构对称化,为下一步的“颜色翻转”做准备。
  • 图示
          Grandparent                 Parent
            / (Red)                  /      \ (Red)
         Parent       ==右旋===>   New(Red)  Grandparent
          / (Red)
        New

④ 规则四:如果同时有左右 red \rightarrow 翻转颜色 (Color Flip),上一层次级变 red

  • 原理:当一个节点的左右孩子都是红色时,这代表在 2-32\text{-}3 树中产生了一个临时的 4-Node [A,B,C][A, B, C]。根据 2-32\text{-}3 树的规则,4-Node 必须分裂,中间元素 BB 向上提并融入父节点。
  • 操作
    1. 将左右孩子的颜色由红变黑(相当于向下分配分裂后的黑色连接)。
    2. 将当前节点自身的颜色由黑变红(相当于把中间元素向上推入父节点,成为父节点的红链接)。
  • 注意:当前节点变红后,可能会导致它的父级节点也产生“右倾红链接”或“连续红链接”冲突。因此,该过程需要自底向上递归级联(Cascading),直到根节点。根节点最后若变红,直接强制变回黑色即可(这对应着 2-32\text{-}3 树增加一层高度的时刻)。

五、 课堂例题与练习解析 (Exercises)

📊 练习 1:判断合法的 LLRB

【题目】:以下四棵红黑树,有多少棵是合法的 LLRB(即能 1-对-1 投影到合法的 2-32\text{-}3 树)? (注:双线表示红链接,单线表示黑链接)

    (1)             (2)             (3)             (4)
     G               G               G               G
    / \             / \             / \             / \
   B   X           B   X           B   X           C   X
  // \            / \             / \\            // \
  A   C          A   C           A   C            A   B

【详细解析】

  • 图 (1) [不合法]:节点 B 有两条红链接(左子 A 和自身作为 G 的左子)。这意味着节点 B2-32\text{-}3 树中既和 G 粘合,又和 A 粘合,形成了一个 4-Node。LLRB 不允许 4-Node 状态持久化。
  • 图 (2) [不合法]GABCX 的空路径上,黑色链接数不平衡。具体而言:
    • A 的路径:G -> B (黑), B -> A (黑),共 2 个黑键。
    • X 的路径:G -> X (黑),共 1 个黑键。
    • 违反了“黑色完美平衡”。
  • 图 (3) [不合法]B -> C 是右倾红链接。LLRB 规定红链接必须左倾。
  • 图 (4) [合法]
    • 所有红链接都是左倾的(C -> A 是红链接)。
    • 完美黑色平衡:从 G 到任意 Null 的黑色高度均为 1(路径 G -> C 是黑的,G -> X 是黑的)。
    • 对应的 2-32\text{-}3 树结构为:根节点是 G,左子是 3-Node [A, C],右子是 X

📊 练习 2:计算 LLRB 的实际高度

【题目】:若某一 2-32\text{-}3 树结构如下(粉色标记的为 3-Nodes,即含有两个元素的节点):

          [ D , E ]                  [ P ]
         /    |    \                /     \
      [ B ] [ G ]  [ J, N ]      [ Q, R ] [ V, W ]

已知该 2-32\text{-}3 树的高度(Tallness/Height)为 3。求它对应的 LLRB 的树高度(即从根到叶子结点的最长路径边数)。

【详细解析】

  1. 分析投影变换

    • 在 LLRB 中,每一个普通的 2-Node 对应 11 条黑链接。
    • 每一个 3-Node 被拆分为两个二叉节点,中间用 11 条红链接连接。
  2. 寻找最长路径

    • 树的深度取决于沿着哪一条路径向下走。为了让路径最长,我们应该选择穿过尽可能多的 3-Nodes(因为 3-Node 会额外贡献一条红链接)。
    • 观察上图:
      • 根节点是 3-Node [D, E] \rightarrow 贡献 11 条黑键,11 条红键。
      • 中间孩子 [J, N] 是 3-Node \rightarrow 贡献 11 条黑键,11 条红键。
      • 叶子节点 [Q, R] 也是 3-Node \rightarrow 贡献 11 条黑键,11 条红键。
  3. 计算高度

    • 该路径上包含的黑色链接数 = 2-32\text{-}3 树的高度 = 33

    • 该路径上包含的红色链接数 = 沿途 3-Nodes 的个数 = 22(注意:最底下的 3-Node 不会向更下方产生红链接)。

    • 故最长路径高度为:

      3 (Black)+2 (Red)=53 \text{ (Black)} + 2 \text{ (Red)} = 5

📊 挑战练习:插入元素 7711 验证平衡

【自主演练】:尝试将 7,6,5,4,3,2,17, 6, 5, 4, 3, 2, 1 依次插入一个初始为空的 LLRB 树中,应用上面的 4 步法则。

【部分过程详解】

  • 插入 7

    • 7(根,黑色)。
  • 插入 6

    • 新插入一律为红,故 6(红) 挂在 7 的左边(合法,无需旋转)。
  • 插入 5

    • 5(红) 挂在 6 的左边。此时出现连续左侧红链接(违反规则三:7 -> 6(红) -> 5(红))。

    • 修复:对 7 执行 rotateRight(7) \rightarrow 结构变为 6 成为根,5(红) 为左子,7(红) 为右子。

    • 此时,6 的左右孩子均为红色(违反规则四)。

    • 修复:对 6 进行 Color Flip \rightarrow 57 变为黑色,6 变为红色(作为根节点,最终被强制设为黑色)。

    • 阶段树形状:

            6 (黑)
           /   \
         5(黑) 7(黑)
    • 树实现完美平衡!

六、 各种搜索树总结 (Search Tree Summary)

树类型平衡机制查找复杂度 O()O(\cdot)插入复杂度 O()O(\cdot)实现复杂度与评价
普通 BST无(依赖插入顺序)最坏 O(N)O(N), 平均 O(logN)O(\log N)最坏 O(N)O(N), 平均 O(logN)O(\log N)极易实现,但容易退化为链表。
2-32\text{-}3 树 (B-Tree)节点分裂与合并(向上回溯)严格 O(logN)O(\log N)严格 O(logN)O(\log N)逻辑极难维护,存在多种节点类型和高昂的转换开销。
左倾红黑树 (LLRB)树旋转与颜色翻转(保持 2-32\text{-}3 树同构)严格 O(logN)O(\log N)严格 O(logN)O(\log N)插入操作极其简洁,代码优美,但删除操作(Delete)依然较难实现。
标准红黑树 (TreeMap)允许左右红链接严格 O(logN)O(\log N)严格 O(logN)O(\log N)Java 中的 TreeMap 对应的是 2-42\text{-}4 树。代码更复杂,但在实际工业运行中,由于减少了旋转次数,速度通常比 LLRB 更快。