Skip to content

红黑树

为什么需要红黑树

普通二叉搜索树(BST)在最坏情况下会退化为链表,查找效率降为 O(n)。AVL 树通过严格的平衡因子(左右子树高度差 ≤ 1)解决了这个问题,但每次插入/删除后可能需要多次旋转来恢复平衡,维护代价较高。

红黑树是一种弱平衡的二叉搜索树。它通过对节点着色并施加约束,保证树的高度不超过 2log₂(n+1),从而在查找效率和维护成本之间取得更好的折中。在 408 考研中,红黑树是树与二叉树章节的重要考点,常与 AVL 树对比考查。

核心思想

红黑树的核心特点:

  • 每个节点非红即黑:用 1 bit 额外空间存储颜色信息
  • 弱平衡策略:不要求左右子树高度严格相等,只要求任意路径上的黑色节点数相同(黑高相等)
  • 最长路径 ≤ 2 × 最短路径:由性质推导得出,保证最坏情况下仍为 O(log n)

黑高(Black Height) 的定义:从某节点出发(不含该节点)到任一叶节点路径上的黑色节点数。整棵树的黑高 = 根节点的黑高。

节点结构:

c
typedef enum { RED, BLACK } Color;

typedef struct RBNode {
    int key;
    Color color;
    struct RBNode *left, *right, *parent;
} RBNode;

交互可视化

通过下方的交互动画,你可以逐步观察红黑树的执行过程:

加载可视化中...

操作详解

五条性质

红黑树必须同时满足以下五条性质:

编号性质说明
每个节点是红色或黑色用颜色标记区分节点
根节点是黑色根必须为黑
叶节点(NIL)是黑色这里的叶节点指外部的空节点,不是普通叶节点
红节点的两个子节点都是黑色即不存在连续的两个红节点("不红红")
从任一节点到其所有叶节点的路径上,黑色节点数目相同即黑高相等

关键推论:由性质④和⑤可得——最长路径(红黑交替)不超过最短路径(全黑)的 2 倍,因此含 n 个内部节点的红黑树高度 h ≤ 2log₂(n+1)

插入操作

红黑树的插入分两步:按 BST 规则插入 → 着色并调整

关键步骤:

  1. 按照二叉搜索树的规则找到插入位置
  2. 新节点染为红色(若染黑则必破坏性质⑤,染红只可能破坏性质④)
  3. 若破坏了红黑性质,则进行调整(变色 / 旋转)
c
// 插入节点(简化版)
void rbInsert(RBTree *T, int key) {
    RBNode *z = createNode(key);
    z->color = RED;  // 新节点染红
    // 按 BST 规则插入 z
    bstInsert(T, z);
    // 插入后调整
    rbInsertFixup(T, z);
}

插入后调整

插入红色节点后,只有当父节点也是红色时才需要调整(违反性质④)。设当前节点为 z,根据叔节点(uncle)的颜色分三种情况:

情况一:叔节点为红色(变色即可)

  • 将父节点和叔节点染,祖父节点染
  • z 指向祖父节点,继续向上检查
        G(黑)              G(红) ← 继续向上
       / \      变色       / \
      P(红) U(红)  →     P(黑) U(黑)
     /                  /
    z(红)              z(红)

情况二:叔节点为黑色,z 是"折线"形(先旋转变直线)

  • z 是父节点的右孩子(父是祖父的左孩子),对 P 左旋,转化为情况三
  • (镜像情况类似,对 P 右旋)

情况三:叔节点为黑色,z 是"直线"形(旋转 + 变色)

  • 对祖父节点 G 右旋(若 P 是 G 的左孩子)
  • P 染黑,G 染红
        G(黑)              P(黑)
       / \     右旋G      / \
      P(红) U(黑)  →    z(红) G(红)
     /                        \
    z(红)                      U(黑)

插入调整最多旋转 2 次,其余操作为 O(log n) 的变色上溯。

c
void rbInsertFixup(RBTree *T, RBNode *z) {
    while (z->parent && z->parent->color == RED) {
        if (z->parent == z->parent->parent->left) {
            RBNode *uncle = z->parent->parent->right;
            if (uncle && uncle->color == RED) {
                // 情况一:叔节点红色
                z->parent->color = BLACK;
                uncle->color = BLACK;
                z->parent->parent->color = RED;
                z = z->parent->parent;
            } else {
                if (z == z->parent->right) {
                    // 情况二:折线 → 左旋转为直线
                    z = z->parent;
                    leftRotate(T, z);
                }
                // 情况三:直线 → 右旋 + 变色
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                rightRotate(T, z->parent->parent);
            }
        } else {
            // 镜像处理(parent 是右孩子,左右互换)
            // ... 对称操作
        }
    }
    T->root->color = BLACK;  // 保证性质②
}

复杂度分析

操作时间复杂度说明
查找O(log n)树高 ≤ 2log₂(n+1)
插入O(log n)查找位置 O(log n) + 调整最多旋转 2 次
删除O(log n)查找位置 O(log n) + 调整最多旋转 3 次

红黑树 vs AVL 树对比

对比项红黑树AVL 树
平衡条件黑高相等(弱平衡)左右子树高度差 ≤ 1(严格平衡)
最大高度2log₂(n+1)1.44log₂(n+2)
查找效率略低于 AVL更优
插入旋转次数≤ 2 次≤ 2 次
删除旋转次数≤ 3 次O(log n) 次
适用场景频繁插入/删除(如 Linux 内核、STL map)查找密集型场景

考研高频考点

  • ⭐ 红黑树的五条性质(选择题/判断题高频,务必逐条记牢)
  • ⭐ 含 n 个内部节点的红黑树高度上界 h ≤ 2log₂(n+1)(填空题/证明题)
  • ⭐ 红黑树 vs AVL 树的对比:平衡条件、旋转次数、适用场景(简答题/选择题常考)
  • ⭐ 插入调整三种情况的判断与操作(叔红变色、叔黑折线双旋、叔黑直线单旋)
  • 黑高的定义与计算(概念题)
  • 新插入节点为什么染红而不染黑(选择题偶考)
  • 红黑树中最短路径与最长路径的关系(最长 ≤ 2 × 最短)