【数据结构】红黑树的基本操作

目录

一、引言

[(一)节点结构与 nil 哨兵设计](#(一)节点结构与 nil 哨兵设计)

(二)核心性质与作用机制

[性质 1:颜色属性](#性质 1:颜色属性)

[性质 2:根节点属性](#性质 2:根节点属性)

[性质 3:nil 节点属性](#性质 3:nil 节点属性)

[性质 4:红色节点约束](#性质 4:红色节点约束)

[性质 5:黑高一致性](#性质 5:黑高一致性)

(三)平衡效果与理论意义

二、红黑树核心操作原理与代码解析

(一)红黑树的核心性质

(二)核心算法详解

[1. 节点结构与初始化](#1. 节点结构与初始化)

[2. 旋转操作(平衡树结构的基础)](#2. 旋转操作(平衡树结构的基础))

左旋(leftRotate(x))

右旋(rightRotate(y))

[3. 插入算法(insert + insertFixup)](#3. 插入算法(insert + insertFixup))

插入节点(insert)

插入后修复(insertFixup(z))

[4. 删除算法(remove + deleteNode + deleteFixup)](#4. 删除算法(remove + deleteNode + deleteFixup))

[查找并删除节点(remove + deleteNode)](#查找并删除节点(remove + deleteNode))

[移植操作(transplant(u, v))](#移植操作(transplant(u, v)))

删除后修复(deleteFixup(x))

[5. 查找算法(search + searchNode)](#5. 查找算法(search + searchNode))

[6. 遍历算法](#6. 遍历算法)

[7. 辅助算法](#7. 辅助算法)

(三)算法总结

三、红黑树的基本操作代码完整实现

(一)C++代码如下:

(二)Python代码如下:

(三)Java代码如下:

四、程序运行结果展示

(一)C++代码运行截图如下:

(二)Python代码运行截图如下:

(三)Java代码运行截图如下:

五、时间复杂度的数学证明

[(一)核心概念:黑高(Black Height)](#(一)核心概念:黑高(Black Height))

树高与黑高的关系:

(二)归纳法证明:节点数下限与树高上限

[1.定理:高度为 h 的红黑树至少包含 个内部节点](#1.定理:高度为 h 的红黑树至少包含 个内部节点)

2.推导树高上限:

(三)操作复杂度分析与对比

1.红黑树操作复杂度:

[2.与普通 BST 的对比](#2.与普通 BST 的对比)

六、与AVL树的对比分析

(一)平衡机制:近似平衡与严格平衡的分野

(二)性能指标:动态操作效率与空间开销的权衡

[2.1 平衡维护成本:旋转次数的数量级差异](#2.1 平衡维护成本:旋转次数的数量级差异)

[2.2 空间开销:1 位 vs 多位的存储成本](#2.2 空间开销:1 位 vs 多位的存储成本)

[2.3 时间复杂度:理论同阶,实践分化](#2.3 时间复杂度:理论同阶,实践分化)

(三)工程选择:场景适配与设计哲学的落地

[3.1 红黑树:动态数据场景的首选](#3.1 红黑树:动态数据场景的首选)

[3.2 AVL 树:静态查询场景的优化选择](#3.2 AVL 树:静态查询场景的优化选择)

(四)对比总结表

七、红黑树的工程应用案

(一)编程语言标准库:有序容器的底层支柱

[(二)Linux 内核 CFS 调度器:进程调度的效率引擎](#(二)Linux 内核 CFS 调度器:进程调度的效率引擎)

[(三)Nginx 定时器:高效事件驱动的核心组件](#(三)Nginx 定时器:高效事件驱动的核心组件)

(四)数据库与缓存:索引与排序的底层支撑

总结:红黑树的技术适配场景

八、实现难点与优化建议

(一)实现难点剖析

(二)优化建议

(三)工程实现与调试方法

九、总结


一、引言

红黑树是一种自平衡二叉搜索树(Binary Search Tree, BST),其本质特征在于通过为每个节点增加颜色属性(红色或黑色)及一系列严格的着色约束,确保树的高度始终维持在近似平衡状态。与普通二叉搜索树可能因插入顺序不当退化为链表(导致操作复杂度降至 \(O(n)\))不同,红黑树通过对从根到叶子的所有路径施加颜色限制,保证最长路径长度不超过最短路径的 2 倍 ,从而使树高始终保持在 \(O(\log n)\) 级别,确保查找、插入、删除等基本操作的最坏时间复杂度为 \(O(\log n)\)。这种平衡机制被称为"近似平衡",既避免了绝对平衡(如 AVL 树)的频繁调整开销,又能满足高效操作的需求。

(一)节点结构与 nil 哨兵设计

红黑树的节点结构在普通二叉搜索树基础上扩展了颜色属性,同时引入** nil 哨兵节点* *(NIL 节点)统一处理边界条件。具体而言,每个节点包含以下 5 个核心属性:

• color:节点颜色,取值为红色(RED)或黑色(BLACK);

• key:节点存储的关键字值;

• left/right:指向左、右子节点的指针;

• p:指向父节点的指针。

其中,nil 哨兵节点是一种特殊的黑色节点,用于表示"空"子节点或父节点。它不存储实际数据,仅作为树结构的边界标记,确保所有叶子节点(非哨兵节点)的子节点均为 nil 节点,从而简化性质校验和操作逻辑。例如,当一个节点的左子节点不存在时,其 left 指针指向 nil 哨兵;根节点的 p 指针同样指向 nil 哨兵。这种设计避免了对"空指针"的特殊处理,使树的结构更统一。

(二)核心性质与作用机制

红黑树的平衡保障依赖于以下 5 个核心性质(红黑性质),这些性质共同约束了树的结构和着色规则:

性质 1:颜色属性

每个节点的颜色为红色或黑色 。这是红黑树的基础定义,颜色作为控制平衡的核心手段,通过后续性质的组合约束实现对路径长度的控制。在代码实现中,通常通过枚举类型定义颜色,例如:

cpp 复制代码
enum Color { RED, BLACK };
性质 2:根节点属性

根节点必须为黑色 。这一性质确保树的"顶层"起始颜色统一,避免因根节点为红色可能导致的路径颜色计算偏差。若根节点在操作中变为红色,需通过颜色调整将其重新置黑,以维持性质成立。

性质 3:nil 节点属性

所有 nil 哨兵节点均为黑色 。nil 节点作为叶子节点的"替身",其黑色属性确保了路径中黑色节点的计数统一。例如,一个叶子节点(非哨兵)的左、右子节点均为 nil 节点,这两个 nil 节点的黑色属性会参与路径黑色节点数量的计算。

性质 4:红色节点约束

若一个节点为红色,则其两个子节点必须为黑色 (即不存在连续的红色节点)。这一性质直接限制了路径中红色节点的密度:红色节点不能相邻,意味着红色节点必须由黑色节点分隔。该约束避免了因红色节点聚集导致的路径过长,是控制路径长度的关键性质之一。

性质 5:黑高一致性

从任意节点到其所有后代 nil 节点的路径中,黑色节点的数量必须相同 。这里的黑色节点数量被定义为该节点的黑高 (Black-Height),记为 bh(x)。例如,若节点 x 的黑高为 3,则从 x 出发的所有路径(直至 nil 节点)均包含 3 个黑色节点(不包含 x 本身)。这一性质是红黑树平衡的核心保障,直接限制了路径长度的差异:最短路径由全黑节点组成(长度等于黑高),最长路径则为红黑节点交替出现(长度不超过黑高的 2 倍),因此最长路径 ≤ 2 × 最短路径

性质协同作用 :性质 4(无连续红节点)与性质 5(黑高一致)的组合,从"红节点间隔"和"黑节点总量"两个维度约束了路径长度。假设某红黑树的黑高为 h,则最短路径长度为 h(全黑节点),最长路径长度为 2h(红黑交替),从而严格保证了树的近似平衡。

(三)平衡效果与理论意义

红黑树的 5 个性质共同确保了其高度的上界为 (其中 n 为节点数)。这一结论可通过反证法推导:设树的黑高为 h,则根据性质 5,树中至少有 个黑色节点(全黑路径构成的完全二叉树);结合性质 4,红色节点数量不超过黑色节点,故总节点数 ,解得 ,进而树高(最长路径)不超过

这种高度控制使得红黑树在动态操作中既能保持高效的时间复杂度,又避免了 AVL 树等绝对平衡结构的频繁旋转开销,因此在工程实践中被广泛应用于关联容器(如 C++ STL 的 std::map)、内核调度等场景。其核心价值在于:通过局部颜色约束 而非全局结构调整实现平衡,以较低的维护成本换取稳定的操作效率。

红黑树的定义与性质是理解其操作原理的基础。后续章节将围绕这些性质,详细阐述插入、删除操作中如何通过旋转和颜色调整维持平衡,而本章所述的 5 个核心性质正是这些操作的约束条件和调整目标。

二、红黑树核心操作原理与代码解析

(一)红黑树的核心性质

红黑树通过维护以下 5 条性质保证平衡,代码中所有操作均围绕这些性质设计:

  1. 颜色性质:每个节点要么是红色(RED),要么是黑色(BLACK)。
  2. 根性质:根节点必须是黑色。
  3. 叶子性质 :所有叶子节点(哨兵节点nil)是黑色。
  4. 红子性质:如果一个节点是红色,则它的两个子节点必须是黑色(即不存在两个连续的红色节点)。
  5. 黑高性质:从任一节点到其所有叶子节点的路径中,黑色节点的数量相同(称为 "黑高")。

(二)核心算法详解

1. 节点结构与初始化
cpp 复制代码
// 红黑树节点结构
template <typename K, typename V>
struct RBNode {
    K key;           // 键
    V value;         // 值
    Color color;     // 颜色
    RBNode *left;    // 左子节点
    RBNode *right;   // 右子节点
    RBNode *parent;  // 父节点

    RBNode(const K& k, const V& v) 
        : key(k), value(v), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};
  • 节点结构(RBNode :包含键(key)、值(value)、颜色(color)、左子节点(left)、右子节点(right)、父节点(parent)。新节点默认颜色为红色(减少对黑高性质的影响)。
  • 哨兵节点(nil :替代NULL,所有空指针均指向nilnil颜色为黑色,简化边界条件处理(如避免判断NULL)。
  • 树初始化 :根节点初始指向nil,树大小为 0。
2. 旋转操作(平衡树结构的基础)

旋转是调整树结构的核心操作,不破坏二叉搜索树的性质(左子树键 < 父节点键 < 右子树键),仅改变节点的父子关系。

左旋(leftRotate(x)
cpp 复制代码
// --- 辅助操作:左旋 ---
void leftRotate(RBNode<K, V>* x) {
    RBNode<K, V>* y = x->right;  // x 的右孩子
    x->right = y->left;          // y 的左子树成为 x 的右子树
    if (y->left != nil) {
        y->left->parent = x;
    }
    y->parent = x->parent;       // x 的父节点成为 y 的父节点
    if (x->parent == nil) {      // x 是根节点时,y 成为新根
        root = y;
    } else if (x == x->parent->left) {  // x 是父的左孩子
        x->parent->left = y;
    } else {  // x 是父的右孩子
        x->parent->right = y;
    }
    y->left = x;   // x 成为 y 的左孩子
    x->parent = y;
}
  • 作用 :将节点x的右子树y提升为x的父节点,x成为y的左子节点。
  • 步骤
    1. y = x->rightx的右子节点)。
    2. y的左子树转为x的右子树(若y->leftnil,更新其 parent 为x)。
    3. 更新y的 parent 为x的 parent(若x是根,则y成为新根;否则x的父节点将y作为左 / 右子节点)。
    4. x设为y的左子节点,更新x的 parent 为y
右旋(rightRotate(y)
cpp 复制代码
// --- 辅助操作:右旋 ---
void rightRotate(RBNode<K, V>* y) {
    RBNode<K, V>* x = y->left;   // y 的左孩子
    y->left = x->right;          // x 的右子树成为 y 的左子树
    if (x->right != nil) {
        x->right->parent = y;
    }
    x->parent = y->parent;       // y 的父节点成为 x 的父节点
    if (y->parent == nil) {      // y 是根节点时,x 成为新根
        root = x;
    } else if (y == y->parent->left) {  // y 是父的左孩子
        y->parent->left = x;
    } else {  // y 是父的右孩子
        y->parent->right = x;
    }
    x->right = y;  // y 成为 x 的右孩子
    y->parent = x;
}
  • 作用 :将节点y的左子树x提升为y的父节点,y成为x的右子节点。
  • 步骤:与左旋对称,将左子树提升,调整父子关系。
3. 插入算法(insert + insertFixup
cpp 复制代码
// --- 插入后修复红黑树性质 ---
void insertFixup(RBNode<K, V>* z) {
    // 当父节点为红色时,违反"红节点的子节点必为黑"的性质,需要修复
    while (z->parent->color == RED) {
        if (z->parent == z->parent->parent->left) {  // 父节点是祖父的左孩子
            RBNode<K, V>* uncle = z->parent->parent->right;  // 叔节点(祖父的右孩子)
            
            if (uncle->color == RED) {  // 情况1:叔节点为红 → 变色即可
                z->parent->color = BLACK;
                uncle->color = BLACK;
                z->parent->parent->color = RED;
                z = z->parent->parent;  // 祖父可能违反性质,继续向上修复
            } else {  // 叔节点为黑
                if (z == z->parent->right) {  // 情况2:z 是父的右孩子 → 先左旋
                    z = z->parent;
                    leftRotate(z);
                }
                // 情况3:z 是父的左孩子 → 父变黑色、祖父变红色,再右旋
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                rightRotate(z->parent->parent);
            }
        } else {  // 对称情况:父节点是祖父的右孩子
            RBNode<K, V>* uncle = z->parent->parent->left;  // 叔节点(祖父的左孩子)
            
            if (uncle->color == RED) {  // 情况1:叔节点为红 → 变色
                z->parent->color = BLACK;
                uncle->color = BLACK;
                z->parent->parent->color = RED;
                z = z->parent->parent;
            } else {  // 叔节点为黑
                if (z == z->parent->left) {  // 情况2:z 是父的左孩子 → 先右旋
                    z = z->parent;
                    rightRotate(z);
                }
                // 情况3:z 是父的右孩子 → 父变黑色、祖父变红色,再左旋
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                leftRotate(z->parent->parent);
            }
        }
    }
    root->color = BLACK;  // 确保根节点始终为黑色
}

插入过程分为两步:先按二叉搜索树规则插入新节点,再修复可能违反的红黑树性质。

插入节点(insert
  • 步骤
    1. 创建新节点z(颜色为红色),查找插入位置(同二叉搜索树:小于当前节点则向左,大于则向右)。
    2. 确定z的父节点parent,将z设为parent的左 / 右子节点(若树为空,z成为根)。
    3. 调用insertFixup(z)修复红黑树性质。
插入后修复(insertFixup(z)
  • 问题:新节点为红色,可能违反 "红子性质"(若父节点也是红色)。

  • 修复逻辑:循环处理,直到父节点为黑色(此时无违反),分 3 种情况(对称处理左右子树):

    • 情况 1 :父节点和叔节点(祖父的另一个子节点)均为红色。解决:将父节点和叔节点改为黑色,祖父改为红色,将z指向祖父(继续向上修复)。(原理:通过变色维持黑高性质,且不产生连续红节点)

    • 情况 2 :父节点为红,叔节点为黑,且z是父节点的右子节点(左子树对称)。解决:对父节点左旋,将z指向父节点,转为情况 3。(原理:通过旋转调整节点位置,统一为情况 3 处理)

    • 情况 3 :父节点为红,叔节点为黑,且z是父节点的左子节点(左子树对称)。解决:父节点改为黑色,祖父改为红色,对祖父右旋。(原理:变色 + 旋转消除连续红节点,维持黑高性质)

  • 最终操作:无论如何,根节点强制设为黑色(保证根性质)。

4. 删除算法(remove + deleteNode + deleteFixup

删除过程最复杂:先按二叉搜索树规则删除节点,再修复可能违反的红黑树性质。

查找并删除节点(remove + deleteNode
cpp 复制代码
// --- 删除节点(内部辅助,与二叉搜索树逻辑结合后修复)---
void deleteNode(RBNode<K, V>* z) {
    RBNode<K, V>* y = z;         // 记录要真正删除的节点
    RBNode<K, V>* x = nil;       // 记录 y 的子节点(用于后续修复)
    Color y_original_color = y->color;  // 记录 y 原始颜色(若为黑,删除后可能破坏性质)

    // 情况1:z 只有右孩子
    if (z->left == nil) {
        x = z->right;
        transplant(z, z->right);
    } 
    // 情况2:z 只有左孩子
    else if (z->right == nil) {
        x = z->left;
        transplant(z, z->left);
    } 
    // 情况3:z 有两个孩子 → 找后继(右子树最小节点)
    else {
        y = minimum(z->right);
        y_original_color = y->color;
        x = y->right;
        if (y->parent == z) {  // 后继是 z 的直接右孩子
            x->parent = y;
        } else {  // 后继不是 z 的直接右孩子 → 先移植后继的右子树
            transplant(y, y->right);
            y->right = z->right;
            y->right->parent = y;
        }
        // 用后继 y 替换 z
        transplant(z, y);
        y->left = z->left;
        y->left->parent = y;
        y->color = z->color;
    }

    // 若删除的是黑色节点,可能破坏性质,需修复
    if (y_original_color == BLACK) {
        deleteFixup(x);
    }

    delete z;  // 释放原节点内存
    treeSize--; // 减少节点计数
}
  • 步骤
    1. 查找目标节点zsearchNode),若不存在则返回失败。
    2. 确定真正删除的节点y
      • z只有一个子节点或无子女,y = z
      • z有两个子女,yz的后继(右子树的最小值,保证二叉搜索树性质)。
    3. y的子节点x替代ytransplant操作,替换父子关系)。
    4. y是黑色(删除黑色节点可能破坏黑高性质),调用deleteFixup(x)修复。
移植操作(transplant(u, v)
cpp 复制代码
// --- 移植操作:用 v 替换 u(二叉搜索树通用操作)---
void transplant(RBNode<K, V>* u, RBNode<K, V>* v) {
    if (u->parent == nil) {
        root = v;
    } else if (u == u->parent->left) {
        u->parent->left = v;
    } else {
        u->parent->right = v;
    }
    v->parent = u->parent;
}
  • 作用 :用子树v替代子树u,仅调整父子关系,不破坏二叉搜索树性质。
  • 步骤 :更新u的父节点与v的关联,以及v的父节点为u的父节点。
删除后修复(deleteFixup(x)
cpp 复制代码
// --- 删除后修复红黑树性质 ---
void deleteFixup(RBNode<K, V>* x) {
    // 当 x 为黑且非根时,可能违反"路径黑节点数相同"的性质,需要修复
    while (x != root && x->color == BLACK) {
        if (x == x->parent->left) {  // x 是父的左孩子
            RBNode<K, V>* sibling = x->parent->right;  // 兄弟节点
            
            if (sibling->color == RED) {  // 情况1:兄弟是红 → 先变色+左旋,将兄弟转为黑
                sibling->color = BLACK;
                x->parent->color = RED;
                leftRotate(x->parent);
                sibling = x->parent->right;
            }

            if (sibling->left->color == BLACK && sibling->right->color == BLACK) {  // 情况2:兄弟的子都是黑 → 兄弟变红,x 上移
                sibling->color = RED;
                x = x->parent;
            } else {
                if (sibling->right->color == BLACK) {  // 情况3:兄弟右子是黑,左子是红 → 兄弟左旋,转为情况4
                    sibling->left->color = BLACK;
                    sibling->color = RED;
                    rightRotate(sibling);
                    sibling = x->parent->right;
                }
                // 情况4:兄弟右子是红 → 变色+左旋,修复完成
                sibling->color = x->parent->color;
                x->parent->color = BLACK;
                sibling->right->color = BLACK;
                leftRotate(x->parent);
                x = root;  // 结束循环
            }
        } else {  // 对称情况:x 是父的右孩子
            RBNode<K, V>* sibling = x->parent->left;  // 兄弟节点
            
            if (sibling->color == RED) {  // 情况1:兄弟是红 → 变色+右旋
                sibling->color = BLACK;
                x->parent->color = RED;
                rightRotate(x->parent);
                sibling = x->parent->left;
            }

            if (sibling->right->color == BLACK && sibling->left->color == BLACK) {  // 情况2:兄弟的子都是黑 → 兄弟变红,x 上移
                sibling->color = RED;
                x = x->parent;
            } else {
                if (sibling->left->color == BLACK) {  // 情况3:兄弟左子是黑,右子是红 → 兄弟右旋,转为情况4
                    sibling->right->color = BLACK;
                    sibling->color = RED;
                    leftRotate(sibling);
                    sibling = x->parent->left;
                }
                // 情况4:兄弟左子是红 → 变色+右旋,修复完成
                sibling->color = x->parent->color;
                x->parent->color = BLACK;
                sibling->left->color = BLACK;
                rightRotate(x->parent);
                x = root;  // 结束循环
            }
        }
    }
    x->color = BLACK;  // 确保 x 最终为黑色(若 x 是根,直接设为黑)
}
  • 问题 :若删除的是黑色节点,x(替代节点)所在路径的黑高减少 1,违反黑高性质;或可能产生连续红节点。

  • 修复逻辑 :循环处理,直到x为红色或x是根,分 4 种情况(对称处理左右子树):

    • 情况 1x的兄弟节点s为红色。解决:s改为黑色,x的父节点改为红色,对父节点左旋,更新s为新的兄弟节点(转为情况 2/3/4)。(原理:将兄弟节点转为黑色,为后续修复做准备)

    • 情况 2s为黑,且s的两个子节点均为黑。解决:s改为红色,x指向父节点(向上传递黑高不足的问题)。(原理:通过将兄弟节点变红,平衡黑高)

    • 情况 3s为黑,s的左子节点为红,右子节点为黑(左子树对称)。解决:s的左子节点改为黑,s改为红,对s右旋,更新s为新的兄弟节点(转为情况 4)。(原理:调整兄弟节点的子树结构,统一为情况 4 处理)

    • 情况 4s为黑,s的右子节点为红(左子树对称)。解决:s继承父节点颜色,父节点改为黑,s的右子节点改为黑,对父节点左旋,x指向根(结束循环)。(原理:通过变色 + 旋转修复黑高,消除连续红节点)

  • 最终操作x强制设为黑色(保证黑高性质)。

5. 查找算法(search + searchNode
cpp 复制代码
// --- 查找节点(内部辅助)---
RBNode<K, V>* searchNode(const K& key) const {
    RBNode<K, V>* curr = root;
    while (curr != nil) {
        if (key < curr->key) {
            curr = curr->left;
        } else if (key > curr->key) {
            curr = curr->right;
        } else {
            return curr;  // 找到节点
        }
    }
    return nil;  // 未找到
}
  • 原理:利用二叉搜索树的性质(左子树键 < 父节点键 < 右子树键)递归查找。
  • 步骤:从根节点开始,若目标键小于当前节点键则向左子树查找,大于则向右子树查找,等于则返回节点。
6. 遍历算法
cpp 复制代码
// --- 前序遍历辅助函数 ---
void preorderHelper(RBNode<K, V>* node, vector<pair<K, V>>& result) const {
    if (node != nil) {
        result.emplace_back(node->key, node->value);
        preorderHelper(node->left, result);
        preorderHelper(node->right, result);
    }
}

// --- 中序遍历辅助函数 ---
void inorderHelper(RBNode<K, V>* node, vector<pair<K, V>>& result) const {
    if (node != nil) {
        inorderHelper(node->left, result);
        result.emplace_back(node->key, node->value);
        inorderHelper(node->right, result);
    }
}

// --- 后序遍历辅助函数 ---
void postorderHelper(RBNode<K, V>* node, vector<pair<K, V>>& result) const {
    if (node != nil) {
        postorderHelper(node->left, result);
        postorderHelper(node->right, result);
        result.emplace_back(node->key, node->value);
    }
}

// --- 层序遍历 ---
vector<pair<K, V>> levelorder() const {
    vector<pair<K, V>> result;
    if (root == nil) return result;

    queue<RBNode<K, V>*> q;
    q.push(root);

    while (!q.empty()) {
        RBNode<K, V>* node = q.front();
        q.pop();
        result.emplace_back(node->key, node->value);

        if (node->left != nil)
            q.push(node->left);
        if (node->right != nil)
            q.push(node->right);
    }
    return result;
}

遍历用于按特定顺序访问所有节点,红黑树的遍历与普通二叉搜索树一致:

  • 前序遍历(preorder:根 → 左子树 → 右子树。
  • 中序遍历(inorder :左子树 → 根 → 右子树(红黑树中序遍历结果为有序序列)。
  • 后序遍历(postorder:左子树 → 右子树 → 根。
  • 层序遍历(levelorder:按层次(从根开始,逐层访问),用队列实现。
7. 辅助算法
cpp 复制代码
// --- 获取树的大小 ---
int size() const {
    return treeSize;
}

// --- 获取树的高度 ---
int height() const {
    return heightHelper(root);
}

// --- 检查树是否为空 ---
bool isEmpty() const {
    return root == nil;
}

// --- 清空树 ---
void clear() {
    destroy(root);
    root = nil;
    treeSize = 0;
}

// --- 查找最小值 ---
bool findMin(K& key, V& value) const {
    if (isEmpty()) return false;
    
    RBNode<K, V>* node = minimum(root);
    key = node->key;
    value = node->value;
    return true;
}

// --- 查找最大值 ---
bool findMax(K& key, V& value) const {
    if (isEmpty()) return false;
    
    RBNode<K, V>* node = maximum(root);
    key = node->key;
    value = node->value;
    return true;
}

// --- 查找前驱节点(小于当前键的最大键)---
bool findPredecessor(const K& key, K& predKey, V& predValue) const {
    RBNode<K, V>* node = searchNode(key);
    if (node == nil) return false;

    // 左子树非空:前驱是左子树的最大值
    if (node->left != nil) {
        RBNode<K, V>* pred = maximum(node->left);
        predKey = pred->key;
        predValue = pred->value;
        return true;
    }

    // 左子树为空:向上找第一个有右子树的祖先
    RBNode<K, V>* pred = node->parent;
    while (pred != nil && node == pred->left) {
        node = pred;
        pred = pred->parent;
    }

    if (pred != nil) {
        predKey = pred->key;
        predValue = pred->value;
        return true;
    }
    
    return false; // 无前列
}

// --- 查找后继节点(大于当前键的最小键)---
bool findSuccessor(const K& key, K& succKey, V& succValue) const {
    RBNode<K, V>* node = searchNode(key);
    if (node == nil) return false;

    // 右子树非空:后继是右子树的最小值
    if (node->right != nil) {
        RBNode<K, V>* succ = minimum(node->right);
        succKey = succ->key;
        succValue = succ->value;
        return true;
    }

    // 右子树为空:向上找第一个有左子树的祖先
    RBNode<K, V>* succ = node->parent;
    while (succ != nil && node == succ->right) {
        node = succ;
        succ = succ->parent;
    }

    if (succ != nil) {
        succKey = succ->key;
        succValue = succ->value;
        return true;
    }
    
    return false; // 无后继
}

// --- 打印树结构 ---
void printStructure() const {
    if (isEmpty()) {
        cout << "Tree is empty" << endl;
        return;
    }
    printStructureHelper(root, "", true);
}

// --- 范围查询:返回键在 [minKey, maxKey] 之间的键值对 ---
vector<pair<K, V>> rangeQuery(const K& minKey, const K& maxKey) const {
    vector<pair<K, V>> result;
    rangeQueryHelper(root, minKey, maxKey, result);
    return result;
}

// --- 统计区间节点数:返回键在 [minKey, maxKey] 之间的节点数量 ---
int countRange(const K& minKey, const K& maxKey) const {
    return countRangeHelper(root, minKey, maxKey);
}

// --- 检查红黑树是否满足所有性质(性质1-5)---
bool checkProperties() const {
    bool valid = true;
    if (!checkColorProperty(root)) {
        cout << "违反性质1:节点颜色不是红色或黑色" << endl;
        valid = false;
    }
    if (!checkRootProperty()) {
        cout << "违反性质2:根节点不是黑色" << endl;
        valid = false;
    }
    if (!checkRedParentProperty(root)) {
        cout << "违反性质4:存在红色节点的子节点为红色" << endl;
        valid = false;
    }
    if (!checkBlackHeightProperty()) {
        cout << "违反性质5:从根到叶的路径黑节点数不同" << endl;
        valid = false;
    }
    if (valid) cout << "红黑树所有性质均满足" << endl;
    return valid;
}
  • 最值查找

    • 最小值(minimum):从节点出发,沿左子树一直到最左节点。
    • 最大值(maximum):从节点出发,沿右子树一直到最右节点。
  • 前驱 / 后继查找

    • 前驱(findPredecessor):小于当前键的最大键。若左子树非空,为左子树的最大值;否则为向上找到的第一个 "当前节点是其右子节点" 的祖先。
    • 后继(findSuccessor):大于当前键的最小键。若右子树非空,为右子树的最小值;否则为向上找到的第一个 "当前节点是其左子节点" 的祖先。
  • 范围查询(rangeQuery :查找键在[minKey, maxKey]之间的所有节点。利用二叉搜索树性质递归:若当前节点键 > minKey则查左子树,若在范围内则记录,若键 < maxKey则查右子树。

  • 性质检查(checkProperties:验证红黑树的 5 条性质是否满足,用于调试(如检查颜色合法性、根是否为黑、红节点的子节点是否为黑、黑高是否一致)。

(三)算法总结

红黑树的核心是通过旋转 (调整结构)和变色 (调整节点颜色)维护 5 条性质,从而保证树的高度始终为O(log n)。代码中:

  • 插入和删除是最复杂的操作,通过insertFixupdeleteFixup修复性质;
  • 旋转是平衡结构的基础,不破坏二叉搜索树的有序性;
  • 其他操作(查找、遍历、最值等)依赖二叉搜索树的基本性质,效率由树的平衡性保证。

三、红黑树的基本操作代码完整实现

(一)C++代码如下:

cpp 复制代码
#include <iostream>
#include <string>
#include <queue>
#include <vector>

using namespace std;

// 颜色枚举:红、黑
enum Color { RED, BLACK };

// 红黑树节点结构
template <typename K, typename V>
struct RBNode {
    K key;           // 键
    V value;         // 值
    Color color;     // 颜色
    RBNode *left;    // 左子节点
    RBNode *right;   // 右子节点
    RBNode *parent;  // 父节点

    RBNode(const K& k, const V& v) 
        : key(k), value(v), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};

// 红黑树类
template <typename K, typename V>
class RedBlackTree {
private:
    RBNode<K, V>* root;  // 根节点
    RBNode<K, V>* nil;   // 哨兵节点(代替 NULL,颜色为 BLACK)
    int treeSize;        // 树中节点数量

    // --- 辅助操作:左旋 ---
    void leftRotate(RBNode<K, V>* x) {
        RBNode<K, V>* y = x->right;  // x 的右孩子
        x->right = y->left;          // y 的左子树成为 x 的右子树
        if (y->left != nil) {
            y->left->parent = x;
        }
        y->parent = x->parent;       // x 的父节点成为 y 的父节点
        if (x->parent == nil) {      // x 是根节点时,y 成为新根
            root = y;
        } else if (x == x->parent->left) {  // x 是父的左孩子
            x->parent->left = y;
        } else {  // x 是父的右孩子
            x->parent->right = y;
        }
        y->left = x;   // x 成为 y 的左孩子
        x->parent = y;
    }

    // --- 辅助操作:右旋 ---
    void rightRotate(RBNode<K, V>* y) {
        RBNode<K, V>* x = y->left;   // y 的左孩子
        y->left = x->right;          // x 的右子树成为 y 的左子树
        if (x->right != nil) {
            x->right->parent = y;
        }
        x->parent = y->parent;       // y 的父节点成为 x 的父节点
        if (y->parent == nil) {      // y 是根节点时,x 成为新根
            root = x;
        } else if (y == y->parent->left) {  // y 是父的左孩子
            y->parent->left = x;
        } else {  // y 是父的右孩子
            y->parent->right = x;
        }
        x->right = y;  // y 成为 x 的右孩子
        y->parent = x;
    }

    // --- 插入后修复红黑树性质 ---
    void insertFixup(RBNode<K, V>* z) {
        // 当父节点为红色时,违反"红节点的子节点必为黑"的性质,需要修复
        while (z->parent->color == RED) {
            if (z->parent == z->parent->parent->left) {  // 父节点是祖父的左孩子
                RBNode<K, V>* uncle = z->parent->parent->right;  // 叔节点(祖父的右孩子)
                
                if (uncle->color == RED) {  // 情况1:叔节点为红 → 变色即可
                    z->parent->color = BLACK;
                    uncle->color = BLACK;
                    z->parent->parent->color = RED;
                    z = z->parent->parent;  // 祖父可能违反性质,继续向上修复
                } else {  // 叔节点为黑
                    if (z == z->parent->right) {  // 情况2:z 是父的右孩子 → 先左旋
                        z = z->parent;
                        leftRotate(z);
                    }
                    // 情况3:z 是父的左孩子 → 父变黑色、祖父变红色,再右旋
                    z->parent->color = BLACK;
                    z->parent->parent->color = RED;
                    rightRotate(z->parent->parent);
                }
            } else {  // 对称情况:父节点是祖父的右孩子
                RBNode<K, V>* uncle = z->parent->parent->left;  // 叔节点(祖父的左孩子)
                
                if (uncle->color == RED) {  // 情况1:叔节点为红 → 变色
                    z->parent->color = BLACK;
                    uncle->color = BLACK;
                    z->parent->parent->color = RED;
                    z = z->parent->parent;
                } else {  // 叔节点为黑
                    if (z == z->parent->left) {  // 情况2:z 是父的左孩子 → 先右旋
                        z = z->parent;
                        rightRotate(z);
                    }
                    // 情况3:z 是父的右孩子 → 父变黑色、祖父变红色,再左旋
                    z->parent->color = BLACK;
                    z->parent->parent->color = RED;
                    leftRotate(z->parent->parent);
                }
            }
        }
        root->color = BLACK;  // 确保根节点始终为黑色
    }

    // --- 查找节点(内部辅助)---
    RBNode<K, V>* searchNode(const K& key) const {
        RBNode<K, V>* curr = root;
        while (curr != nil) {
            if (key < curr->key) {
                curr = curr->left;
            } else if (key > curr->key) {
                curr = curr->right;
            } else {
                return curr;  // 找到节点
            }
        }
        return nil;  // 未找到
    }

    // --- 找子树中最小节点(用于删除时找后继)---
    RBNode<K, V>* minimum(RBNode<K, V>* node) const {
        while (node->left != nil) {
            node = node->left;
        }
        return node;
    }

    // --- 找子树中最大节点 ---
    RBNode<K, V>* maximum(RBNode<K, V>* node) const {
        while (node->right != nil) {
            node = node->right;
        }
        return node;
    }

    // --- 删除后修复红黑树性质 ---
    void deleteFixup(RBNode<K, V>* x) {
        // 当 x 为黑且非根时,可能违反"路径黑节点数相同"的性质,需要修复
        while (x != root && x->color == BLACK) {
            if (x == x->parent->left) {  // x 是父的左孩子
                RBNode<K, V>* sibling = x->parent->right;  // 兄弟节点
                
                if (sibling->color == RED) {  // 情况1:兄弟是红 → 先变色+左旋,将兄弟转为黑
                    sibling->color = BLACK;
                    x->parent->color = RED;
                    leftRotate(x->parent);
                    sibling = x->parent->right;
                }

                if (sibling->left->color == BLACK && sibling->right->color == BLACK) {  // 情况2:兄弟的子都是黑 → 兄弟变红,x 上移
                    sibling->color = RED;
                    x = x->parent;
                } else {
                    if (sibling->right->color == BLACK) {  // 情况3:兄弟右子是黑,左子是红 → 兄弟左旋,转为情况4
                        sibling->left->color = BLACK;
                        sibling->color = RED;
                        rightRotate(sibling);
                        sibling = x->parent->right;
                    }
                    // 情况4:兄弟右子是红 → 变色+左旋,修复完成
                    sibling->color = x->parent->color;
                    x->parent->color = BLACK;
                    sibling->right->color = BLACK;
                    leftRotate(x->parent);
                    x = root;  // 结束循环
                }
            } else {  // 对称情况:x 是父的右孩子
                RBNode<K, V>* sibling = x->parent->left;  // 兄弟节点
                
                if (sibling->color == RED) {  // 情况1:兄弟是红 → 变色+右旋
                    sibling->color = BLACK;
                    x->parent->color = RED;
                    rightRotate(x->parent);
                    sibling = x->parent->left;
                }

                if (sibling->right->color == BLACK && sibling->left->color == BLACK) {  // 情况2:兄弟的子都是黑 → 兄弟变红,x 上移
                    sibling->color = RED;
                    x = x->parent;
                } else {
                    if (sibling->left->color == BLACK) {  // 情况3:兄弟左子是黑,右子是红 → 兄弟右旋,转为情况4
                        sibling->right->color = BLACK;
                        sibling->color = RED;
                        leftRotate(sibling);
                        sibling = x->parent->left;
                    }
                    // 情况4:兄弟左子是红 → 变色+右旋,修复完成
                    sibling->color = x->parent->color;
                    x->parent->color = BLACK;
                    sibling->left->color = BLACK;
                    rightRotate(x->parent);
                    x = root;  // 结束循环
                }
            }
        }
        x->color = BLACK;  // 确保 x 最终为黑色(若 x 是根,直接设为黑)
    }

    // --- 移植操作:用 v 替换 u(二叉搜索树通用操作)---
    void transplant(RBNode<K, V>* u, RBNode<K, V>* v) {
        if (u->parent == nil) {
            root = v;
        } else if (u == u->parent->left) {
            u->parent->left = v;
        } else {
            u->parent->right = v;
        }
        v->parent = u->parent;
    }

    // --- 删除节点(内部辅助,与二叉搜索树逻辑结合后修复)---
    void deleteNode(RBNode<K, V>* z) {
        RBNode<K, V>* y = z;         // 记录要真正删除的节点
        RBNode<K, V>* x = nil;       // 记录 y 的子节点(用于后续修复)
        Color y_original_color = y->color;  // 记录 y 原始颜色(若为黑,删除后可能破坏性质)

        // 情况1:z 只有右孩子
        if (z->left == nil) {
            x = z->right;
            transplant(z, z->right);
        } 
        // 情况2:z 只有左孩子
        else if (z->right == nil) {
            x = z->left;
            transplant(z, z->left);
        } 
        // 情况3:z 有两个孩子 → 找后继(右子树最小节点)
        else {
            y = minimum(z->right);
            y_original_color = y->color;
            x = y->right;
            if (y->parent == z) {  // 后继是 z 的直接右孩子
                x->parent = y;
            } else {  // 后继不是 z 的直接右孩子 → 先移植后继的右子树
                transplant(y, y->right);
                y->right = z->right;
                y->right->parent = y;
            }
            // 用后继 y 替换 z
            transplant(z, y);
            y->left = z->left;
            y->left->parent = y;
            y->color = z->color;
        }

        // 若删除的是黑色节点,可能破坏性质,需修复
        if (y_original_color == BLACK) {
            deleteFixup(x);
        }

        delete z;  // 释放原节点内存
        treeSize--; // 减少节点计数
    }

    // --- 销毁树(析构时用)---
    void destroy(RBNode<K, V>* node) {
        if (node != nil) {
            destroy(node->left);
            destroy(node->right);
            delete node;
        }
    }

    // --- 前序遍历辅助函数 ---
    void preorderHelper(RBNode<K, V>* node, vector<pair<K, V>>& result) const {
        if (node != nil) {
            result.emplace_back(node->key, node->value);
            preorderHelper(node->left, result);
            preorderHelper(node->right, result);
        }
    }

    // --- 中序遍历辅助函数 ---
    void inorderHelper(RBNode<K, V>* node, vector<pair<K, V>>& result) const {
        if (node != nil) {
            inorderHelper(node->left, result);
            result.emplace_back(node->key, node->value);
            inorderHelper(node->right, result);
        }
    }

    // --- 后序遍历辅助函数 ---
    void postorderHelper(RBNode<K, V>* node, vector<pair<K, V>>& result) const {
        if (node != nil) {
            postorderHelper(node->left, result);
            postorderHelper(node->right, result);
            result.emplace_back(node->key, node->value);
        }
    }

    // --- 计算树高度辅助函数 ---
    int heightHelper(RBNode<K, V>* node) const {
        if (node == nil) {
            return 0;
        }
        int leftHeight = heightHelper(node->left);
        int rightHeight = heightHelper(node->right);
        return max(leftHeight, rightHeight) + 1;
    }

    // --- 打印树结构辅助函数 ---
    void printStructureHelper(RBNode<K, V>* node, string indent, bool last) const {
        if (node != nil) {
            cout << indent;
            if (last) {
                cout << "R----";
                indent += "   ";
            } else {
                cout << "L----";
                indent += "|  ";
            }
            
            string color = (node->color == RED) ? "RED" : "BLACK";
            cout << node->key << "(" << color << ")" << endl;
            printStructureHelper(node->left, indent, false);
            printStructureHelper(node->right, indent, true);
        }
    }

    // --- 范围查询辅助函数 ---
    void rangeQueryHelper(RBNode<K, V>* node, const K& minKey, const K& maxKey, vector<pair<K, V>>& result) const {
        if (node == nil) return;
        
        // 左子树可能有符合条件的节点
        if (node->key > minKey) {
            rangeQueryHelper(node->left, minKey, maxKey, result);
        }
        
        // 当前节点在范围内,加入结果
        if (node->key >= minKey && node->key <= maxKey) {
            result.emplace_back(node->key, node->value);
        }
        
        // 右子树可能有符合条件的节点
        if (node->key < maxKey) {
            rangeQueryHelper(node->right, minKey, maxKey, result);
        }
    }

    // --- 统计区间节点数辅助函数 ---
    int countRangeHelper(RBNode<K, V>* node, const K& minKey, const K& maxKey) const {
        if (node == nil) return 0;
        
        int count = 0;
        // 当前节点在范围内,计数+1
        if (node->key >= minKey && node->key <= maxKey) {
            count = 1;
        }
        
        // 左子树递归统计
        if (node->key > minKey) {
            count += countRangeHelper(node->left, minKey, maxKey);
        }
        
        // 右子树递归统计
        if (node->key < maxKey) {
            count += countRangeHelper(node->right, minKey, maxKey);
        }
        
        return count;
    }

    // --- 检查红黑树性质:性质1(颜色合法性)---
    bool checkColorProperty(RBNode<K, V>* node) const {
        if (node == nil) return true;
        if (node->color != RED && node->color != BLACK) return false;
        return checkColorProperty(node->left) && checkColorProperty(node->right);
    }

    // --- 检查红黑树性质:性质2(根为黑色)---
    bool checkRootProperty() const {
        return root->color == BLACK;
    }

    // --- 检查红黑树性质:性质4(红节点的子节点为黑)---
    bool checkRedParentProperty(RBNode<K, V>* node) const {
        if (node == nil) return true;
        if (node->color == RED) {
            if (node->left->color == RED || node->right->color == RED) {
                return false;
            }
        }
        return checkRedParentProperty(node->left) && checkRedParentProperty(node->right);
    }

    // --- 检查红黑树性质:性质5(每条路径黑节点数相同)---
    int blackHeight(RBNode<K, V>* node) const {
        if (node == nil) return 1; // 外部节点(nil)的黑高为1
        int leftBH = blackHeight(node->left);
        int rightBH = blackHeight(node->right);
        if (leftBH != rightBH) return -1; // 左右黑高不同,违反性质
        return leftBH + (node->color == BLACK ? 1 : 0);
    }
    bool checkBlackHeightProperty() const {
        return blackHeight(root) != -1;
    }

public:
    // 构造函数:初始化哨兵和根
    RedBlackTree() {
        nil = new RBNode<K, V>(K(), V());
        nil->color = BLACK;
        root = nil;
        treeSize = 0;
    }

    // 析构函数:销毁所有节点
    ~RedBlackTree() {
        destroy(root);
        delete nil;
    }

    // --- 对外插入接口 ---
    void insert(const K& key, const V& value) {
        RBNode<K, V>* z = new RBNode<K, V>(key, value);
        z->left = z->right = z->parent = nil;  // 新节点的子、父初始指向哨兵

        RBNode<K, V>* parent = nil;
        RBNode<K, V>* curr = root;

        // 找插入位置(同二叉搜索树)
        while (curr != nil) {
            parent = curr;
            if (z->key < curr->key) {
                curr = curr->left;
            } else {
                curr = curr->right;
            }
        }

        z->parent = parent;
        if (parent == nil) {  // 树为空,新节点为根
            root = z;
        } else if (z->key < parent->key) {  // 插在父的左子树
            parent->left = z;
        } else {  // 插在父的右子树
            parent->right = z;
        }

        insertFixup(z);  // 修复红黑树性质
        treeSize++;      // 增加节点计数
    }

    // --- 对外查找接口 ---
    bool search(const K& key, V& value) const {
        RBNode<K, V>* node = searchNode(key);
        if (node != nil) {
            value = node->value;
            return true;
        }
        return false;
    }

    // --- 对外删除接口 ---
    bool remove(const K& key) {
        RBNode<K, V>* node = searchNode(key);
        if (node == nil) {
            return false;  // 未找到节点
        }
        deleteNode(node);
        return true;
    }

    // --- 更新节点值 ---
    bool update(const K& key, const V& newValue) {
        RBNode<K, V>* node = searchNode(key);
        if (node != nil) {
            node->value = newValue;
            return true;
        }
        return false;
    }

    // --- 前序遍历 ---
    vector<pair<K, V>> preorder() const {
        vector<pair<K, V>> result;
        preorderHelper(root, result);
        return result;
    }

    // --- 中序遍历 ---
    vector<pair<K, V>> inorder() const {
        vector<pair<K, V>> result;
        inorderHelper(root, result);
        return result;
    }

    // --- 后序遍历 ---
    vector<pair<K, V>> postorder() const {
        vector<pair<K, V>> result;
        postorderHelper(root, result);
        return result;
    }

    // --- 层序遍历 ---
    vector<pair<K, V>> levelorder() const {
        vector<pair<K, V>> result;
        if (root == nil) return result;

        queue<RBNode<K, V>*> q;
        q.push(root);

        while (!q.empty()) {
            RBNode<K, V>* node = q.front();
            q.pop();
            result.emplace_back(node->key, node->value);

            if (node->left != nil)
                q.push(node->left);
            if (node->right != nil)
                q.push(node->right);
        }
        return result;
    }

    // --- 获取树的大小 ---
    int size() const {
        return treeSize;
    }

    // --- 获取树的高度 ---
    int height() const {
        return heightHelper(root);
    }

    // --- 检查树是否为空 ---
    bool isEmpty() const {
        return root == nil;
    }

    // --- 清空树 ---
    void clear() {
        destroy(root);
        root = nil;
        treeSize = 0;
    }

    // --- 查找最小值 ---
    bool findMin(K& key, V& value) const {
        if (isEmpty()) return false;
        
        RBNode<K, V>* node = minimum(root);
        key = node->key;
        value = node->value;
        return true;
    }

    // --- 查找最大值 ---
    bool findMax(K& key, V& value) const {
        if (isEmpty()) return false;
        
        RBNode<K, V>* node = maximum(root);
        key = node->key;
        value = node->value;
        return true;
    }

    // --- 查找前驱节点(小于当前键的最大键)---
    bool findPredecessor(const K& key, K& predKey, V& predValue) const {
        RBNode<K, V>* node = searchNode(key);
        if (node == nil) return false;

        // 左子树非空:前驱是左子树的最大值
        if (node->left != nil) {
            RBNode<K, V>* pred = maximum(node->left);
            predKey = pred->key;
            predValue = pred->value;
            return true;
        }

        // 左子树为空:向上找第一个有右子树的祖先
        RBNode<K, V>* pred = node->parent;
        while (pred != nil && node == pred->left) {
            node = pred;
            pred = pred->parent;
        }

        if (pred != nil) {
            predKey = pred->key;
            predValue = pred->value;
            return true;
        }
        
        return false; // 无前列
    }

    // --- 查找后继节点(大于当前键的最小键)---
    bool findSuccessor(const K& key, K& succKey, V& succValue) const {
        RBNode<K, V>* node = searchNode(key);
        if (node == nil) return false;

        // 右子树非空:后继是右子树的最小值
        if (node->right != nil) {
            RBNode<K, V>* succ = minimum(node->right);
            succKey = succ->key;
            succValue = succ->value;
            return true;
        }

        // 右子树为空:向上找第一个有左子树的祖先
        RBNode<K, V>* succ = node->parent;
        while (succ != nil && node == succ->right) {
            node = succ;
            succ = succ->parent;
        }

        if (succ != nil) {
            succKey = succ->key;
            succValue = succ->value;
            return true;
        }
        
        return false; // 无后继
    }

    // --- 打印树结构 ---
    void printStructure() const {
        if (isEmpty()) {
            cout << "Tree is empty" << endl;
            return;
        }
        printStructureHelper(root, "", true);
    }

    // --- 范围查询:返回键在 [minKey, maxKey] 之间的键值对 ---
    vector<pair<K, V>> rangeQuery(const K& minKey, const K& maxKey) const {
        vector<pair<K, V>> result;
        rangeQueryHelper(root, minKey, maxKey, result);
        return result;
    }

    // --- 统计区间节点数:返回键在 [minKey, maxKey] 之间的节点数量 ---
    int countRange(const K& minKey, const K& maxKey) const {
        return countRangeHelper(root, minKey, maxKey);
    }

    // --- 检查红黑树是否满足所有性质(性质1-5)---
    bool checkProperties() const {
        bool valid = true;
        if (!checkColorProperty(root)) {
            cout << "违反性质1:节点颜色不是红色或黑色" << endl;
            valid = false;
        }
        if (!checkRootProperty()) {
            cout << "违反性质2:根节点不是黑色" << endl;
            valid = false;
        }
        if (!checkRedParentProperty(root)) {
            cout << "违反性质4:存在红色节点的子节点为红色" << endl;
            valid = false;
        }
        if (!checkBlackHeightProperty()) {
            cout << "违反性质5:从根到叶的路径黑节点数不同" << endl;
            valid = false;
        }
        if (valid) cout << "红黑树所有性质均满足" << endl;
        return valid;
    }
};

int main() {
    // 测试<int, string>类型的红黑树
    RedBlackTree<int, string> rbt;

    cout << "=== 测试插入操作 ===" << endl;
    rbt.insert(10, "Ten");
    rbt.insert(20, "Twenty");
    rbt.insert(5, "Five");
    rbt.insert(15, "Fifteen");
    rbt.insert(30, "Thirty");
    rbt.insert(25, "Twenty-five");
    rbt.insert(35, "Thirty-five");
    
    cout << "树的大小: " << rbt.size() << endl;
    cout << "树的高度: " << rbt.height() << endl;
    
    cout << "\n=== 测试树结构 ===" << endl;
    rbt.printStructure();

    cout << "\n=== 测试查找操作 ===" << endl;
    string val;
    if (rbt.search(10, val)) {
        cout << "找到键 10: 值 = " << val << endl;
    } else {
        cout << "未找到键 10!" << endl;
    }

    if (rbt.search(15, val)) {
        cout << "找到键 15: 值 = " << val << endl;
    }

    cout << "\n=== 测试更新操作 ===" << endl;
    if (rbt.update(10, "Ten Updated")) {
        if (rbt.search(10, val)) {
            cout << "更新后键 10 的值: " << val << endl;
        }
    }

    cout << "\n=== 测试遍历操作 ===" << endl;
    
    auto preorder = rbt.preorder();
    cout << "前序遍历: ";
    for (const auto& p : preorder) cout << p.first << " ";
    cout << endl;
    
    auto inorder = rbt.inorder();
    cout << "中序遍历: ";
    for (const auto& p : inorder) cout << p.first << " ";
    cout << endl;
    
    auto postorder = rbt.postorder();
    cout << "后序遍历: ";
    for (const auto& p : postorder) cout << p.first << " ";
    cout << endl;
    
    auto levelorder = rbt.levelorder();
    cout << "层序遍历: ";
    for (const auto& p : levelorder) cout << p.first << " ";
    cout << endl;

    cout << "\n=== 测试最大最小值 ===" << endl;
    int minKey, maxKey;
    string minVal, maxVal;
    if (rbt.findMin(minKey, minVal)) {
        cout << "最小值: " << minKey << " (" << minVal << ")" << endl;
    }
    if (rbt.findMax(maxKey, maxVal)) {
        cout << "最大值: " << maxKey << " (" << maxVal << ")" << endl;
    }

    cout << "\n=== 测试前驱后继 ===" << endl;
    int predKey, succKey;
    string predVal, succVal;
    if (rbt.findPredecessor(20, predKey, predVal)) {
        cout << "20 的前驱: " << predKey << " (" << predVal << ")" << endl;
    }
    if (rbt.findSuccessor(20, succKey, succVal)) {
        cout << "20 的后继: " << succKey << " (" << succVal << ")" << endl;
    }

    cout << "\n=== 测试删除操作 ===" << endl;
    if (rbt.remove(10)) {
        cout << "已删除键 10" << endl;
        if (!rbt.search(10, val)) {
            cout << "确认键 10 已删除" << endl;
        }
    }
    
    cout << "删除后树的大小: " << rbt.size() << endl;
    cout << "删除后树结构: " << endl;
    rbt.printStructure();

    cout << "\n=== 测试范围查询 ===" << endl;
    auto range = rbt.rangeQuery(15, 30);
    cout << "键在 15 到 30 之间的节点: " << endl;
    for (const auto& p : range) {
        cout << "键: " << p.first << ", 值: " << p.second << endl;
    }
    cout << "该区间内节点数量: " << rbt.countRange(15, 30) << endl;

    cout << "\n=== 测试红黑树性质检查 ===" << endl;
    rbt.checkProperties();

    cout << "\n=== 测试清空操作 ===" << endl;
    rbt.clear();
    cout << "清空后树的大小: " << rbt.size() << endl;
    cout << "树是否为空: " << (rbt.isEmpty() ? "是" : "否") << endl;

    return 0;
}

(二)Python代码如下:

python 复制代码
# 颜色枚举:红、黑
class Color:
    RED = 0
    BLACK = 1


# 红黑树节点类
class RBNode:
    def __init__(self, key, value):
        self.key = key  # 键
        self.value = value  # 值
        self.color = Color.RED  # 颜色,新节点默认为红色
        self.left = None  # 左子节点
        self.right = None  # 右子节点
        self.parent = None  # 父节点


# 红黑树类
class RedBlackTree:
    def __init__(self):
        # 哨兵节点,代替None,颜色为黑色
        self.nil = RBNode(None, None)
        self.nil.color = Color.BLACK
        self.root = self.nil  # 根节点
        self.tree_size = 0  # 树中节点数量

    # --- 辅助操作:左旋 ---
    def left_rotate(self, x):
        y = x.right  # y是x的右孩子
        x.right = y.left

        if y.left != self.nil:
            y.left.parent = x

        y.parent = x.parent

        if x.parent == self.nil:
            self.root = y
        elif x == x.parent.left:
            x.parent.left = y
        else:
            x.parent.right = y

        y.left = x
        x.parent = y

    # --- 辅助操作:右旋 ---
    def right_rotate(self, y):
        x = y.left  # x是y的左孩子
        y.left = x.right

        if x.right != self.nil:
            x.right.parent = y

        x.parent = y.parent

        if y.parent == self.nil:
            self.root = x
        elif y == y.parent.left:
            y.parent.left = x
        else:
            y.parent.right = x

        x.right = y
        y.parent = x

    # --- 插入后修复红黑树性质 ---
    def insert_fixup(self, z):
        # 当父节点为红色时,可能违反红黑树性质
        while z.parent.color == Color.RED:
            if z.parent == z.parent.parent.left:
                # 父节点是祖父的左孩子
                uncle = z.parent.parent.right

                if uncle.color == Color.RED:
                    # 情况1:叔节点为红,只需变色
                    z.parent.color = Color.BLACK
                    uncle.color = Color.BLACK
                    z.parent.parent.color = Color.RED
                    z = z.parent.parent  # 继续向上修复
                else:
                    # 叔节点为黑
                    if z == z.parent.right:
                        # 情况2:z是父节点的右孩子,先左旋
                        z = z.parent
                        self.left_rotate(z)
                    # 情况3:z是父节点的左孩子,变色并右旋
                    z.parent.color = Color.BLACK
                    z.parent.parent.color = Color.RED
                    self.right_rotate(z.parent.parent)
            else:
                # 父节点是祖父的右孩子,对称情况
                uncle = z.parent.parent.left

                if uncle.color == Color.RED:
                    # 情况1:叔节点为红,只需变色
                    z.parent.color = Color.BLACK
                    uncle.color = Color.BLACK
                    z.parent.parent.color = Color.RED
                    z = z.parent.parent  # 继续向上修复
                else:
                    # 叔节点为黑
                    if z == z.parent.left:
                        # 情况2:z是父节点的左孩子,先右旋
                        z = z.parent
                        self.right_rotate(z)
                    # 情况3:z是父节点的右孩子,变色并左旋
                    z.parent.color = Color.BLACK
                    z.parent.parent.color = Color.RED
                    self.left_rotate(z.parent.parent)

        # 确保根节点始终为黑色
        self.root.color = Color.BLACK

    # --- 查找节点(内部辅助)---
    def _search_node(self, key):
        curr = self.root
        while curr != self.nil:
            if key < curr.key:
                curr = curr.left
            elif key > curr.key:
                curr = curr.right
            else:
                return curr  # 找到节点
        return self.nil  # 未找到

    # --- 找子树中最小节点(用于删除时找后继)---
    def _minimum(self, node):
        while node.left != self.nil:
            node = node.left
        return node

    # --- 找子树中最大节点 ---
    def _maximum(self, node):
        while node.right != self.nil:
            node = node.right
        return node

    # --- 删除后修复红黑树性质 ---
    def delete_fixup(self, x):
        # 当x为黑且非根时,可能违反红黑树性质
        while x != self.root and x.color == Color.BLACK:
            if x == x.parent.left:
                # x是父节点的左孩子
                sibling = x.parent.right

                if sibling.color == Color.RED:
                    # 情况1:兄弟是红,变色并左旋
                    sibling.color = Color.BLACK
                    x.parent.color = Color.RED
                    self.left_rotate(x.parent)
                    sibling = x.parent.right

                if (sibling.left.color == Color.BLACK and
                        sibling.right.color == Color.BLACK):
                    # 情况2:兄弟的两个孩子都是黑
                    sibling.color = Color.RED
                    x = x.parent
                else:
                    if sibling.right.color == Color.BLACK:
                        # 情况3:兄弟右孩子是黑,左孩子是红
                        sibling.left.color = Color.BLACK
                        sibling.color = Color.RED
                        self.right_rotate(sibling)
                        sibling = x.parent.right

                    # 情况4:兄弟右孩子是红
                    sibling.color = x.parent.color
                    x.parent.color = Color.BLACK
                    sibling.right.color = Color.BLACK
                    self.left_rotate(x.parent)
                    x = self.root  # 结束循环
            else:
                # x是父节点的右孩子,对称情况
                sibling = x.parent.left

                if sibling.color == Color.RED:
                    # 情况1:兄弟是红,变色并右旋
                    sibling.color = Color.BLACK
                    x.parent.color = Color.RED
                    self.right_rotate(x.parent)
                    sibling = x.parent.left

                if (sibling.right.color == Color.BLACK and
                        sibling.left.color == Color.BLACK):
                    # 情况2:兄弟的两个孩子都是黑
                    sibling.color = Color.RED
                    x = x.parent
                else:
                    if sibling.left.color == Color.BLACK:
                        # 情况3:兄弟左孩子是黑,右孩子是红
                        sibling.right.color = Color.BLACK
                        sibling.color = Color.RED
                        self.left_rotate(sibling)
                        sibling = x.parent.left

                    # 情况4:兄弟左孩子是红
                    sibling.color = x.parent.color
                    x.parent.color = Color.BLACK
                    sibling.left.color = Color.BLACK
                    self.right_rotate(x.parent)
                    x = self.root  # 结束循环

        # 确保x最终为黑色
        x.color = Color.BLACK

    # --- 移植操作:用v替换u ---
    def _transplant(self, u, v):
        if u.parent == self.nil:
            self.root = v
        elif u == u.parent.left:
            u.parent.left = v
        else:
            u.parent.right = v
        v.parent = u.parent

    # --- 删除节点(内部辅助)---
    def _delete_node(self, z):
        y = z
        y_original_color = y.color
        x = self.nil

        # 情况1:z只有右孩子
        if z.left == self.nil:
            x = z.right
            self._transplant(z, z.right)
        # 情况2:z只有左孩子
        elif z.right == self.nil:
            x = z.left
            self._transplant(z, z.left)
        # 情况3:z有两个孩子
        else:
            y = self._minimum(z.right)
            y_original_color = y.color
            x = y.right

            if y.parent == z:
                x.parent = y
            else:
                self._transplant(y, y.right)
                y.right = z.right
                y.right.parent = y

            self._transplant(z, y)
            y.left = z.left
            y.left.parent = y
            y.color = z.color

        # 若删除的是黑色节点,可能破坏性质,需修复
        if y_original_color == Color.BLACK:
            self.delete_fixup(x)

        self.tree_size -= 1

    # --- 销毁树(内部辅助)---
    def _destroy(self, node):
        if node != self.nil:
            self._destroy(node.left)
            self._destroy(node.right)

    # --- 前序遍历辅助函数 ---
    def _preorder_helper(self, node, result):
        if node != self.nil:
            result.append((node.key, node.value))
            self._preorder_helper(node.left, result)
            self._preorder_helper(node.right, result)

    # --- 中序遍历辅助函数 ---
    def _inorder_helper(self, node, result):
        if node != self.nil:
            self._inorder_helper(node.left, result)
            result.append((node.key, node.value))
            self._inorder_helper(node.right, result)

    # --- 后序遍历辅助函数 ---
    def _postorder_helper(self, node, result):
        if node != self.nil:
            self._postorder_helper(node.left, result)
            self._postorder_helper(node.right, result)
            result.append((node.key, node.value))

    # --- 计算树高度辅助函数 ---
    def _height_helper(self, node):
        if node == self.nil:
            return 0
        left_height = self._height_helper(node.left)
        right_height = self._height_helper(node.right)
        return max(left_height, right_height) + 1

    # --- 打印树结构辅助函数 ---
    def _print_structure_helper(self, node, indent, last):
        if node != self.nil:
            print(indent, end="")
            if last:
                print("R----", end="")
                indent += "   "
            else:
                print("L----", end="")
                indent += "|  "

            color = "RED" if node.color == Color.RED else "BLACK"
            print(f"{node.key}({color})")
            self._print_structure_helper(node.left, indent, False)
            self._print_structure_helper(node.right, indent, True)

    # --- 范围查询辅助函数 ---
    def _range_query_helper(self, node, min_key, max_key, result):
        if node == self.nil:
            return

        # 左子树可能有符合条件的节点
        if node.key > min_key:
            self._range_query_helper(node.left, min_key, max_key, result)

        # 当前节点在范围内,加入结果
        if min_key <= node.key <= max_key:
            result.append((node.key, node.value))

        # 右子树可能有符合条件的节点
        if node.key < max_key:
            self._range_query_helper(node.right, min_key, max_key, result)

    # --- 统计区间节点数辅助函数 ---
    def _count_range_helper(self, node, min_key, max_key):
        if node == self.nil:
            return 0

        count = 0
        # 当前节点在范围内,计数+1
        if min_key <= node.key <= max_key:
            count = 1

        # 左子树递归统计
        if node.key > min_key:
            count += self._count_range_helper(node.left, min_key, max_key)

        # 右子树递归统计
        if node.key < max_key:
            count += self._count_range_helper(node.right, min_key, max_key)

        return count

    # --- 检查红黑树性质:性质1(颜色合法性)---
    def _check_color_property(self, node):
        if node == self.nil:
            return True
        if node.color not in (Color.RED, Color.BLACK):
            return False
        return (self._check_color_property(node.left) and
                self._check_color_property(node.right))

    # --- 检查红黑树性质:性质4(红节点的子节点为黑)---
    def _check_red_parent_property(self, node):
        if node == self.nil:
            return True
        if node.color == Color.RED:
            if (node.left.color == Color.RED or
                    node.right.color == Color.RED):
                return False
        return (self._check_red_parent_property(node.left) and
                self._check_red_parent_property(node.right))

    # --- 检查红黑树性质:性质5(每条路径黑节点数相同)---
    def _black_height(self, node):
        if node == self.nil:
            return 1  # 外部节点的黑高为1
        left_bh = self._black_height(node.left)
        right_bh = self._black_height(node.right)
        if left_bh != right_bh:
            return -1  # 左右黑高不同,违反性质
        return left_bh + (1 if node.color == Color.BLACK else 0)

    # --- 对外插入接口 ---
    def insert(self, key, value):
        z = RBNode(key, value)
        z.left = self.nil
        z.right = self.nil
        z.parent = self.nil

        parent = self.nil
        curr = self.root

        # 找插入位置
        while curr != self.nil:
            parent = curr
            if z.key < curr.key:
                curr = curr.left
            else:
                curr = curr.right

        z.parent = parent
        if parent == self.nil:
            self.root = z  # 树为空,新节点为根
        elif z.key < parent.key:
            parent.left = z  # 插在父的左子树
        else:
            parent.right = z  # 插在父的右子树

        self.insert_fixup(z)  # 修复红黑树性质
        self.tree_size += 1  # 增加节点计数

    # --- 对外查找接口 ---
    def search(self, key):
        node = self._search_node(key)
        if node != self.nil:
            return node.value
        return None

    # --- 对外删除接口 ---
    def remove(self, key):
        node = self._search_node(key)
        if node == self.nil:
            return False  # 未找到节点
        self._delete_node(node)
        return True

    # --- 更新节点值 ---
    def update(self, key, new_value):
        node = self._search_node(key)
        if node != self.nil:
            node.value = new_value
            return True
        return False

    # --- 前序遍历 ---
    def preorder(self):
        result = []
        self._preorder_helper(self.root, result)
        return result

    # --- 中序遍历 ---
    def inorder(self):
        result = []
        self._inorder_helper(self.root, result)
        return result

    # --- 后序遍历 ---
    def postorder(self):
        result = []
        self._postorder_helper(self.root, result)
        return result

    # --- 层序遍历 ---
    def levelorder(self):
        result = []
        if self.root == self.nil:
            return result

        from collections import deque
        q = deque()
        q.append(self.root)

        while q:
            node = q.popleft()
            result.append((node.key, node.value))

            if node.left != self.nil:
                q.append(node.left)
            if node.right != self.nil:
                q.append(node.right)

        return result

    # --- 获取树的大小 ---
    def size(self):
        return self.tree_size

    # --- 获取树的高度 ---
    def height(self):
        return self._height_helper(self.root)

    # --- 检查树是否为空 ---
    def is_empty(self):
        return self.root == self.nil

    # --- 清空树 ---
    def clear(self):
        self._destroy(self.root)
        self.root = self.nil
        self.tree_size = 0

    # --- 查找最小值 ---
    def find_min(self):
        if self.is_empty():
            return None

        node = self._minimum(self.root)
        return (node.key, node.value)

    # --- 查找最大值 ---
    def find_max(self):
        if self.is_empty():
            return None

        node = self._maximum(self.root)
        return (node.key, node.value)

    # --- 查找前驱节点(小于当前键的最大键)---
    def find_predecessor(self, key):
        node = self._search_node(key)
        if node == self.nil:
            return None

        # 左子树非空:前驱是左子树的最大值
        if node.left != self.nil:
            pred = self._maximum(node.left)
            return (pred.key, pred.value)

        # 左子树为空:向上找第一个有右子树的祖先
        pred = node.parent
        while pred != self.nil and node == pred.left:
            node = pred
            pred = pred.parent

        if pred != self.nil:
            return (pred.key, pred.value)

        return None  # 无前驱

    # --- 查找后继节点(大于当前键的最小键)---
    def find_successor(self, key):
        node = self._search_node(key)
        if node == self.nil:
            return None

        # 右子树非空:后继是右子树的最小值
        if node.right != self.nil:
            succ = self._minimum(node.right)
            return (succ.key, succ.value)

        # 右子树为空:向上找第一个有左子树的祖先
        succ = node.parent
        while succ != self.nil and node == succ.right:
            node = succ
            succ = succ.parent

        if succ != self.nil:
            return (succ.key, succ.value)

        return None  # 无后继

    # --- 打印树结构 ---
    def print_structure(self):
        if self.is_empty():
            print("Tree is empty")
            return
        self._print_structure_helper(self.root, "", True)

    # --- 范围查询:返回键在 [min_key, max_key] 之间的键值对 ---
    def range_query(self, min_key, max_key):
        result = []
        self._range_query_helper(self.root, min_key, max_key, result)
        return result

    # --- 统计区间节点数:返回键在 [min_key, max_key] 之间的节点数量 ---
    def count_range(self, min_key, max_key):
        return self._count_range_helper(self.root, min_key, max_key)

    # --- 检查红黑树是否满足所有性质(性质1-5)---
    def check_properties(self):
        valid = True

        # 性质1:每个节点不是红色就是黑色
        if not self._check_color_property(self.root):
            print("违反性质1:节点颜色不是红色或黑色")
            valid = False

        # 性质2:根节点是黑色
        if self.root.color != Color.BLACK:
            print("违反性质2:根节点不是黑色")
            valid = False

        # 性质4:如果一个节点是红色,则它的两个子节点都是黑色
        if not self._check_red_parent_property(self.root):
            print("违反性质4:存在红色节点的子节点为红色")
            valid = False

        # 性质5:从任一节点到其所有后代叶节点的简单路径上,黑色节点的数量相同
        if self._black_height(self.root) == -1:
            print("违反性质5:从根到叶的路径黑节点数不同")
            valid = False

        if valid:
            print("红黑树所有性质均满足")
        return valid


# 测试红黑树
def main():
    # 创建红黑树实例
    rbt = RedBlackTree()

    print("=== 测试插入操作 ===")
    rbt.insert(10, "Ten")
    rbt.insert(20, "Twenty")
    rbt.insert(5, "Five")
    rbt.insert(15, "Fifteen")
    rbt.insert(30, "Thirty")
    rbt.insert(25, "Twenty-five")
    rbt.insert(35, "Thirty-five")

    print(f"树的大小: {rbt.size()}")
    print(f"树的高度: {rbt.height()}")

    print("\n=== 测试树结构 ===")
    rbt.print_structure()

    print("\n=== 测试查找操作 ===")
    val = rbt.search(10)
    if val is not None:
        print(f"找到键 10: 值 = {val}")
    else:
        print("未找到键 10!")

    val = rbt.search(15)
    if val is not None:
        print(f"找到键 15: 值 = {val}")

    print("\n=== 测试更新操作 ===")
    if rbt.update(10, "Ten Updated"):
        val = rbt.search(10)
        if val is not None:
            print(f"更新后键 10 的值: {val}")

    print("\n=== 测试遍历操作 ===")

    preorder = rbt.preorder()
    print("前序遍历: ", end="")
    for p in preorder:
        print(p[0], end=" ")
    print()

    inorder = rbt.inorder()
    print("中序遍历: ", end="")
    for p in inorder:
        print(p[0], end=" ")
    print()

    postorder = rbt.postorder()
    print("后序遍历: ", end="")
    for p in postorder:
        print(p[0], end=" ")
    print()

    levelorder = rbt.levelorder()
    print("层序遍历: ", end="")
    for p in levelorder:
        print(p[0], end=" ")
    print()

    print("\n=== 测试最大最小值 ===")
    min_node = rbt.find_min()
    if min_node:
        print(f"最小值: {min_node[0]} ({min_node[1]})")

    max_node = rbt.find_max()
    if max_node:
        print(f"最大值: {max_node[0]} ({max_node[1]})")

    print("\n=== 测试前驱后继 ===")
    pred = rbt.find_predecessor(20)
    if pred:
        print(f"20 的前驱: {pred[0]} ({pred[1]})")

    succ = rbt.find_successor(20)
    if succ:
        print(f"20 的后继: {succ[0]} ({succ[1]})")

    print("\n=== 测试删除操作 ===")
    if rbt.remove(10):
        print("已删除键 10")
        if rbt.search(10) is None:
            print("确认键 10 已删除")

    print(f"删除后树的大小: {rbt.size()}")
    print("删除后树结构: ")
    rbt.print_structure()

    print("\n=== 测试范围查询 ===")
    range_result = rbt.range_query(15, 30)
    print("键在 15 到 30 之间的节点: ")
    for p in range_result:
        print(f"键: {p[0]}, 值: {p[1]}")
    print(f"该区间内节点数量: {rbt.count_range(15, 30)}")

    print("\n=== 测试红黑树性质检查 ===")
    rbt.check_properties()

    print("\n=== 测试清空操作 ===")
    rbt.clear()
    print(f"清空后树的大小: {rbt.size()}")
    print(f"树是否为空: {'是' if rbt.is_empty() else '否'}")


if __name__ == "__main__":
    main()

(三)Java代码如下:

java 复制代码
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Map.Entry;
import java.util.AbstractMap.SimpleEntry;

// 颜色枚举
enum Color {
    RED, BLACK
}

// 红黑树节点类
class RBNode<K, V> {
    K key;
    V value;
    Color color;
    RBNode<K, V> left;
    RBNode<K, V> right;
    RBNode<K, V> parent;

    RBNode(K key, V value) {
        this.key = key;
        this.value = value;
        this.color = Color.RED;
        this.left = null;
        this.right = null;
        this.parent = null;
    }
}

// 红黑树类(泛型约束:K必须实现Comparable接口以支持键比较)
public class RedBlackTree<K extends Comparable<K>, V> {
    private RBNode<K, V> root;
    private final RBNode<K, V> nil; // 哨兵节点(代替null,颜色为BLACK)
    private int treeSize;

    public RedBlackTree() {
        nil = new RBNode<>(null, null);
        nil.color = Color.BLACK;
        root = nil;
        treeSize = 0;
    }

    // --- 辅助操作:左旋 ---
    private void leftRotate(RBNode<K, V> x) {
        RBNode<K, V> y = x.right;
        x.right = y.left;
        if (y.left != nil) {
            y.left.parent = x;
        }
        y.parent = x.parent;
        if (x.parent == nil) {
            root = y;
        } else if (x == x.parent.left) {
            x.parent.left = y;
        } else {
            x.parent.right = y;
        }
        y.left = x;
        x.parent = y;
    }

    // --- 辅助操作:右旋 ---
    private void rightRotate(RBNode<K, V> y) {
        RBNode<K, V> x = y.left;
        y.left = x.right;
        if (x.right != nil) {
            x.right.parent = y;
        }
        x.parent = y.parent;
        if (y.parent == nil) {
            root = x;
        } else if (y == y.parent.left) {
            y.parent.left = x;
        } else {
            y.parent.right = x;
        }
        x.right = y;
        y.parent = x;
    }

    // --- 插入后修复红黑树性质 ---
    private void insertFixup(RBNode<K, V> z) {
        while (z.parent.color == Color.RED) {
            if (z.parent == z.parent.parent.left) {
                RBNode<K, V> uncle = z.parent.parent.right;
                if (uncle.color == Color.RED) {
                    z.parent.color = Color.BLACK;
                    uncle.color = Color.BLACK;
                    z.parent.parent.color = Color.RED;
                    z = z.parent.parent;
                } else {
                    if (z == z.parent.right) {
                        z = z.parent;
                        leftRotate(z);
                    }
                    z.parent.color = Color.BLACK;
                    z.parent.parent.color = Color.RED;
                    rightRotate(z.parent.parent);
                }
            } else {
                RBNode<K, V> uncle = z.parent.parent.left;
                if (uncle.color == Color.RED) {
                    z.parent.color = Color.BLACK;
                    uncle.color = Color.BLACK;
                    z.parent.parent.color = Color.RED;
                    z = z.parent.parent;
                } else {
                    if (z == z.parent.left) {
                        z = z.parent;
                        rightRotate(z);
                    }
                    z.parent.color = Color.BLACK;
                    z.parent.parent.color = Color.RED;
                    leftRotate(z.parent.parent);
                }
            }
        }
        root.color = Color.BLACK;
    }

    // --- 查找节点(内部辅助)---
    private RBNode<K, V> searchNode(K key) {
        RBNode<K, V> curr = root;
        while (curr != nil) {
            int cmp = key.compareTo(curr.key);
            if (cmp < 0) {
                curr = curr.left;
            } else if (cmp > 0) {
                curr = curr.right;
            } else {
                return curr; // 找到节点
            }
        }
        return nil; // 未找到
    }

    // --- 找子树中最小节点(用于删除时找后继)---
    private RBNode<K, V> minimum(RBNode<K, V> node) {
        while (node.left != nil) {
            node = node.left;
        }
        return node;
    }

    // --- 找子树中最大节点 ---
    private RBNode<K, V> maximum(RBNode<K, V> node) {
        while (node.right != nil) {
            node = node.right;
        }
        return node;
    }

    // --- 删除后修复红黑树性质 ---
    private void deleteFixup(RBNode<K, V> x) {
        while (x != root && x.color == Color.BLACK) {
            if (x == x.parent.left) {
                RBNode<K, V> sibling = x.parent.right;
                if (sibling.color == Color.RED) {
                    sibling.color = Color.BLACK;
                    x.parent.color = Color.RED;
                    leftRotate(x.parent);
                    sibling = x.parent.right;
                }
                if (sibling.left.color == Color.BLACK && sibling.right.color == Color.BLACK) {
                    sibling.color = Color.RED;
                    x = x.parent;
                } else {
                    if (sibling.right.color == Color.BLACK) {
                        sibling.left.color = Color.BLACK;
                        sibling.color = Color.RED;
                        rightRotate(sibling);
                        sibling = x.parent.right;
                    }
                    sibling.color = x.parent.color;
                    x.parent.color = Color.BLACK;
                    sibling.right.color = Color.BLACK;
                    leftRotate(x.parent);
                    x = root;
                }
            } else {
                RBNode<K, V> sibling = x.parent.left;
                if (sibling.color == Color.RED) {
                    sibling.color = Color.BLACK;
                    x.parent.color = Color.RED;
                    rightRotate(x.parent);
                    sibling = x.parent.left;
                }
                if (sibling.right.color == Color.BLACK && sibling.left.color == Color.BLACK) {
                    sibling.color = Color.RED;
                    x = x.parent;
                } else {
                    if (sibling.left.color == Color.BLACK) {
                        sibling.right.color = Color.BLACK;
                        sibling.color = Color.RED;
                        leftRotate(sibling);
                        sibling = x.parent.left;
                    }
                    sibling.color = x.parent.color;
                    x.parent.color = Color.BLACK;
                    sibling.left.color = Color.BLACK;
                    rightRotate(x.parent);
                    x = root;
                }
            }
        }
        x.color = Color.BLACK;
    }

    // --- 移植操作:用v替换u(二叉搜索树通用操作)---
    private void transplant(RBNode<K, V> u, RBNode<K, V> v) {
        if (u.parent == nil) {
            root = v;
        } else if (u == u.parent.left) {
            u.parent.left = v;
        } else {
            u.parent.right = v;
        }
        v.parent = u.parent;
    }

    // --- 删除节点(内部辅助,与二叉搜索树逻辑结合后修复)---
    private void deleteNode(RBNode<K, V> z) {
        RBNode<K, V> y = z;
        RBNode<K, V> x = nil;
        Color yOriginalColor = y.color;

        if (z.left == nil) {
            x = z.right;
            transplant(z, z.right);
        } else if (z.right == nil) {
            x = z.left;
            transplant(z, z.left);
        } else {
            y = minimum(z.right);
            yOriginalColor = y.color;
            x = y.right;
            if (y.parent == z) {
                x.parent = y;
            } else {
                transplant(y, y.right);
                y.right = z.right;
                y.right.parent = y;
            }
            transplant(z, y);
            y.left = z.left;
            y.left.parent = y;
            y.color = z.color;
        }

        if (yOriginalColor == Color.BLACK) {
            deleteFixup(x);
        }

        treeSize--;
    }

    // --- 前序遍历辅助函数 ---
    private void preorderHelper(RBNode<K, V> node, List<Entry<K, V>> result) {
        if (node != nil) {
            result.add(new SimpleEntry<>(node.key, node.value));
            preorderHelper(node.left, result);
            preorderHelper(node.right, result);
        }
    }

    // --- 中序遍历辅助函数 ---
    private void inorderHelper(RBNode<K, V> node, List<Entry<K, V>> result) {
        if (node != nil) {
            inorderHelper(node.left, result);
            result.add(new SimpleEntry<>(node.key, node.value));
            inorderHelper(node.right, result);
        }
    }

    // --- 后序遍历辅助函数 ---
    private void postorderHelper(RBNode<K, V> node, List<Entry<K, V>> result) {
        if (node != nil) {
            postorderHelper(node.left, result);
            postorderHelper(node.right, result);
            result.add(new SimpleEntry<>(node.key, node.value));
        }
    }

    // --- 计算树高度辅助函数 ---
    private int heightHelper(RBNode<K, V> node) {
        if (node == nil) {
            return 0;
        }
        int leftHeight = heightHelper(node.left);
        int rightHeight = heightHelper(node.right);
        return Math.max(leftHeight, rightHeight) + 1;
    }

    // --- 打印树结构辅助函数 ---
    private void printStructureHelper(RBNode<K, V> node, String indent, boolean last) {
        if (node != nil) {
            System.out.print(indent);
            if (last) {
                System.out.print("R----");
                indent += "   ";
            } else {
                System.out.print("L----");
                indent += "|  ";
            }
            String color = (node.color == Color.RED) ? "RED" : "BLACK";
            System.out.println(node.key + "(" + color + ")");
            printStructureHelper(node.left, indent, false);
            printStructureHelper(node.right, indent, true);
        }
    }

    // --- 范围查询辅助函数 ---
    private void rangeQueryHelper(RBNode<K, V> node, K minKey, K maxKey, List<Entry<K, V>> result) {
        if (node == nil) return;

        if (node.key.compareTo(minKey) > 0) {
            rangeQueryHelper(node.left, minKey, maxKey, result);
        }

        if (node.key.compareTo(minKey) >= 0 && node.key.compareTo(maxKey) <= 0) {
            result.add(new SimpleEntry<>(node.key, node.value));
        }

        if (node.key.compareTo(maxKey) < 0) {
            rangeQueryHelper(node.right, minKey, maxKey, result);
        }
    }

    // --- 统计区间节点数辅助函数 ---
    private int countRangeHelper(RBNode<K, V> node, K minKey, K maxKey) {
        if (node == nil) return 0;

        int count = 0;
        if (node.key.compareTo(minKey) >= 0 && node.key.compareTo(maxKey) <= 0) {
            count = 1;
        }

        if (node.key.compareTo(minKey) > 0) {
            count += countRangeHelper(node.left, minKey, maxKey);
        }

        if (node.key.compareTo(maxKey) < 0) {
            count += countRangeHelper(node.right, minKey, maxKey);
        }

        return count;
    }

    // --- 检查红黑树性质:性质1(颜色合法性)---
    private boolean checkColorProperty(RBNode<K, V> node) {
        if (node == nil) return true;
        if (node.color != Color.RED && node.color != Color.BLACK) return false;
        return checkColorProperty(node.left) && checkColorProperty(node.right);
    }

    // --- 检查红黑树性质:性质2(根为黑色)---
    private boolean checkRootProperty() {
        return root.color == Color.BLACK;
    }

    // --- 检查红黑树性质:性质4(红节点的子节点为黑)---
    private boolean checkRedParentProperty(RBNode<K, V> node) {
        if (node == nil) return true;
        if (node.color == Color.RED) {
            if (node.left.color == Color.RED || node.right.color == Color.RED) {
                return false;
            }
        }
        return checkRedParentProperty(node.left) && checkRedParentProperty(node.right);
    }

    // --- 检查红黑树性质:性质5(每条路径黑节点数相同)---
    private int blackHeight(RBNode<K, V> node) {
        if (node == nil) return 1; // 外部节点(nil)的黑高为1
        int leftBH = blackHeight(node.left);
        int rightBH = blackHeight(node.right);
        if (leftBH != rightBH) return -1; // 左右黑高不同,违反性质
        return leftBH + (node.color == Color.BLACK ? 1 : 0);
    }

    private boolean checkBlackHeightProperty() {
        return blackHeight(root) != -1;
    }

    // ====================== 对外接口 ======================

    // --- 对外插入接口 ---
    public void insert(K key, V value) {
        RBNode<K, V> z = new RBNode<>(key, value);
        z.left = nil;
        z.right = nil;
        z.parent = nil;

        RBNode<K, V> parent = nil;
        RBNode<K, V> curr = root;

        // 找插入位置(同二叉搜索树)
        while (curr != nil) {
            parent = curr;
            int cmp = key.compareTo(curr.key);
            if (cmp < 0) {
                curr = curr.left;
            } else {
                curr = curr.right;
            }
        }

        z.parent = parent;
        if (parent == nil) { // 树为空,新节点为根
            root = z;
        } else if (key.compareTo(parent.key) < 0) { // 插在父的左子树
            parent.left = z;
        } else { // 插在父的右子树
            parent.right = z;
        }

        insertFixup(z); // 修复红黑树性质
        treeSize++;     // 增加节点计数
    }

    // --- 对外查找接口 ---
    public V search(K key) {
        RBNode<K, V> node = searchNode(key);
        if (node != nil) {
            return node.value;
        }
        return null;
    }

    // --- 对外删除接口 ---
    public boolean remove(K key) {
        RBNode<K, V> node = searchNode(key);
        if (node == nil) {
            return false; // 未找到节点
        }
        deleteNode(node);
        return true;
    }

    // --- 更新节点值 ---
    public boolean update(K key, V newValue) {
        RBNode<K, V> node = searchNode(key);
        if (node != nil) {
            node.value = newValue;
            return true;
        }
        return false;
    }

    // --- 前序遍历 ---
    public List<Entry<K, V>> preorder() {
        List<Entry<K, V>> result = new ArrayList<>();
        preorderHelper(root, result);
        return result;
    }

    // --- 中序遍历 ---
    public List<Entry<K, V>> inorder() {
        List<Entry<K, V>> result = new ArrayList<>();
        inorderHelper(root, result);
        return result;
    }

    // --- 后序遍历 ---
    public List<Entry<K, V>> postorder() {
        List<Entry<K, V>> result = new ArrayList<>();
        postorderHelper(root, result);
        return result;
    }

    // --- 层序遍历 ---
    public List<Entry<K, V>> levelorder() {
        List<Entry<K, V>> result = new ArrayList<>();
        if (root == nil) return result;

        Queue<RBNode<K, V>> q = new LinkedList<>();
        q.offer(root);

        while (!q.isEmpty()) {
            RBNode<K, V> node = q.poll();
            result.add(new SimpleEntry<>(node.key, node.value));

            if (node.left != nil)
                q.offer(node.left);
            if (node.right != nil)
                q.offer(node.right);
        }
        return result;
    }

    // --- 获取树的大小 ---
    public int size() {
        return treeSize;
    }

    // --- 获取树的高度 ---
    public int height() {
        return heightHelper(root);
    }

    // --- 检查树是否为空 ---
    public boolean isEmpty() {
        return root == nil;
    }

    // --- 清空树 ---
    public void clear() {
        root = nil;
        treeSize = 0;
    }

    // --- 查找最小值 ---
    public Entry<K, V> findMin() {
        if (isEmpty()) return null;
        RBNode<K, V> node = minimum(root);
        return new SimpleEntry<>(node.key, node.value);
    }

    // --- 查找最大值 ---
    public Entry<K, V> findMax() {
        if (isEmpty()) return null;
        RBNode<K, V> node = maximum(root);
        return new SimpleEntry<>(node.key, node.value);
    }

    // --- 查找前驱节点(小于当前键的最大键)---
    public Entry<K, V> findPredecessor(K key) {
        RBNode<K, V> node = searchNode(key);
        if (node == nil) return null;

        // 左子树非空:前驱是左子树的最大值
        if (node.left != nil) {
            RBNode<K, V> pred = maximum(node.left);
            return new SimpleEntry<>(pred.key, pred.value);
        }

        // 左子树为空:向上找第一个有右子树的祖先
        RBNode<K, V> pred = node.parent;
        while (pred != nil && node == pred.left) {
            node = pred;
            pred = pred.parent;
        }

        if (pred != nil) {
            return new SimpleEntry<>(pred.key, pred.value);
        }
        return null;
    }

    // --- 查找后继节点(大于当前键的最小键)---
    public Entry<K, V> findSuccessor(K key) {
        RBNode<K, V> node = searchNode(key);
        if (node == nil) return null;

        // 右子树非空:后继是右子树的最小值
        if (node.right != nil) {
            RBNode<K, V> succ = minimum(node.right);
            return new SimpleEntry<>(succ.key, succ.value);
        }

        // 右子树为空:向上找第一个有左子树的祖先
        RBNode<K, V> succ = node.parent;
        while (succ != nil && node == succ.right) {
            node = succ;
            succ = succ.parent;
        }

        if (succ != nil) {
            return new SimpleEntry<>(succ.key, succ.value);
        }
        return null;
    }

    // --- 打印树结构 ---
    public void printStructure() {
        if (isEmpty()) {
            System.out.println("Tree is empty");
            return;
        }
        printStructureHelper(root, "", true);
    }

    // --- 范围查询:返回键在 [minKey, maxKey] 之间的键值对 ---
    public List<Entry<K, V>> rangeQuery(K minKey, K maxKey) {
        List<Entry<K, V>> result = new ArrayList<>();
        rangeQueryHelper(root, minKey, maxKey, result);
        return result;
    }

    // --- 统计区间节点数:返回键在 [minKey, maxKey] 之间的节点数量 ---
    public int countRange(K minKey, K maxKey) {
        return countRangeHelper(root, minKey, maxKey);
    }

    // --- 检查红黑树是否满足所有性质(性质1-5)---
    public boolean checkProperties() {
        boolean valid = true;
        if (!checkColorProperty(root)) {
            System.out.println("违反性质1:节点颜色不是红色或黑色");
            valid = false;
        }
        if (!checkRootProperty()) {
            System.out.println("违反性质2:根节点不是黑色");
            valid = false;
        }
        if (!checkRedParentProperty(root)) {
            System.out.println("违反性质4:存在红色节点的子节点为红色");
            valid = false;
        }
        if (!checkBlackHeightProperty()) {
            System.out.println("违反性质5:从根到叶的路径黑节点数不同");
            valid = false;
        }
        if (valid) System.out.println("红黑树所有性质均满足");
        return valid;
    }

    // ====================== 测试方法 ======================
    public static void main(String[] args) {
        RedBlackTree<Integer, String> rbt = new RedBlackTree<>();

        System.out.println("=== 测试插入操作 ===");
        rbt.insert(10, "Ten");
        rbt.insert(20, "Twenty");
        rbt.insert(5, "Five");
        rbt.insert(15, "Fifteen");
        rbt.insert(30, "Thirty");
        rbt.insert(25, "Twenty-five");
        rbt.insert(35, "Thirty-five");

        System.out.println("树的大小: " + rbt.size());
        System.out.println("树的高度: " + rbt.height());

        System.out.println("\n=== 测试树结构 ===");
        rbt.printStructure();

        System.out.println("\n=== 测试查找操作 ===");
        String val = rbt.search(10);
        if (val != null) {
            System.out.println("找到键 10: 值 = " + val);
        } else {
            System.out.println("未找到键 10!");
        }

        val = rbt.search(15);
        if (val != null) {
            System.out.println("找到键 15: 值 = " + val);
        }

        System.out.println("\n=== 测试更新操作 ===");
        if (rbt.update(10, "Ten Updated")) {
            val = rbt.search(10);
            if (val != null) {
                System.out.println("更新后键 10 的值: " + val);
            }
        }

        System.out.println("\n=== 测试遍历操作 ===");

        List<Entry<Integer, String>> preorder = rbt.preorder();
        System.out.print("前序遍历: ");
        for (Entry<Integer, String> p : preorder) {
            System.out.print(p.getKey() + " ");
        }
        System.out.println();

        List<Entry<Integer, String>> inorder = rbt.inorder();
        System.out.print("中序遍历: ");
        for (Entry<Integer, String> p : inorder) {
            System.out.print(p.getKey() + " ");
        }
        System.out.println();

        List<Entry<Integer, String>> postorder = rbt.postorder();
        System.out.print("后序遍历: ");
        for (Entry<Integer, String> p : postorder) {
            System.out.print(p.getKey() + " ");
        }
        System.out.println();

        List<Entry<Integer, String>> levelorder = rbt.levelorder();
        System.out.print("层序遍历: ");
        for (Entry<Integer, String> p : levelorder) {
            System.out.print(p.getKey() + " ");
        }
        System.out.println();

        System.out.println("\n=== 测试最大最小值 ===");
        Entry<Integer, String> minNode = rbt.findMin();
        if (minNode != null) {
            System.out.println("最小值: " + minNode.getKey() + " (" + minNode.getValue() + ")");
        }

        Entry<Integer, String> maxNode = rbt.findMax();
        if (maxNode != null) {
            System.out.println("最大值: " + maxNode.getKey() + " (" + maxNode.getValue() + ")");
        }

        System.out.println("\n=== 测试前驱后继 ===");
        Entry<Integer, String> pred = rbt.findPredecessor(20);
        if (pred != null) {
            System.out.println("20 的前驱: " + pred.getKey() + " (" + pred.getValue() + ")");
        }

        Entry<Integer, String> succ = rbt.findSuccessor(20);
        if (succ != null) {
            System.out.println("20 的后继: " + succ.getKey() + " (" + succ.getValue() + ")");
        }

        System.out.println("\n=== 测试删除操作 ===");
        if (rbt.remove(10)) {
            System.out.println("已删除键 10");
            if (rbt.search(10) == null) {
                System.out.println("确认键 10 已删除");
            }
        }

        System.out.println("删除后树的大小: " + rbt.size());
        System.out.println("删除后树结构: ");
        rbt.printStructure();

        System.out.println("\n=== 测试范围查询 ===");
        List<Entry<Integer, String>> range = rbt.rangeQuery(15, 30);
        System.out.println("键在 15 到 30 之间的节点: ");
        for (Entry<Integer, String> p : range) {
            System.out.println("键: " + p.getKey() + ", 值: " + p.getValue());
        }
        System.out.println("该区间内节点数量: " + rbt.countRange(15, 30));

        System.out.println("\n=== 测试红黑树性质检查 ===");
        rbt.checkProperties();

        System.out.println("\n=== 测试清空操作 ===");
        rbt.clear();
        System.out.println("清空后树的大小: " + rbt.size());
        System.out.println("树是否为空: " + (rbt.isEmpty() ? "是" : "否"));
    }
}

四、程序运行结果展示

(一)C++代码运行截图如下:

(二)Python代码运行截图如下:

(三)Java代码运行截图如下:

五、时间复杂度的数学证明

红黑树的查询、插入、删除操作均能保持 O(log n) 的时间复杂度,其核心在于通过自平衡机制严格限制树高的增长。以下从数学角度严谨证明这一结论,关键在于推导树高 h 与节点数 n 的关系不等式

(一)核心概念:黑高(Black Height)

黑高 (记为 bh(x) )是红黑树平衡性分析的基础度量,定义为:从节点 x 出发(不包含 x 自身)到任意后代叶节点的路径上,黑色节点的数量。例如,若根节点到叶节点的路径包含 3 个黑色节点(不含根),则根节点的黑高 bh(root) = 3 。

树高与黑高的关系:

红黑树的性质4(红色节点的子节点必为黑色 )确保路径中不会出现连续红色节点,结合性质5(所有叶节点到根的黑色节点数相等 ),可推导出树高与黑高的关键关系:

最长路径分析 :从根到叶的最长路径必然是红黑节点交替出现的情况(如黑→红→黑→红...)。此时,黑色节点数为 bh(root) ,红色节点数最多不超过 bh(root) (否则会违反性质4),因此总路径长度(树高 h )满足

最短路径分析 :全黑路径的长度为 bh(root) ,故

综上,树高 h 与根节点黑高 bh(root) 的关系为:

(二)归纳法证明:节点数下限与树高上限

1.定理:高度为 h 的红黑树至少包含 个内部节点

证明步骤

  1. 基础情况 :当 h = 0 时,树为空,内部节点数为 0,满足 ,命题成立。

  2. 归纳假设 :假设高度为 h-1 的红黑树至少包含 个内部节点。

  3. 归纳步骤 :考虑高度为 h 的红黑树,其根节点的左右子树高度均不超过 h-1 。由黑高定义,根节点的黑高 ,则子节点的黑高至少为 (若子节点为黑色)或 (若子节点为红色,其子节点必为黑色,黑高不变)。

根据归纳假设,每个子树至少包含 个内部节点,因此整树节点数:

2.推导树高上限:

由上述定理 ,整理得:

即红黑树的高度 h 与节点数 n 呈对数关系,故

(三)操作复杂度分析与对比

1.红黑树操作复杂度:

查找 :路径长度等于树高 h ,故时间复杂度为

插入/删除 :基础操作(如查找插入位置)耗时 ,修复平衡(旋转 O(1) 、变色 )的循环次数与树高成正比,总时间仍为

关键结论 :红黑树通过限制树高 ,确保所有操作在最坏情况下仍保持 复杂度,远优于普通二叉搜索树(BST)在最坏情况下的 O(n)(如退化为链表时的查询耗时)。

2.与普通 BST 的对比

普通 BST 在随机数据下表现良好,但在有序数据插入时会退化为链表(如依次插入 1,2,3,4...),此时树高 h = n ,查询、插入、删除操作均退化为 O(n) 。而红黑树通过旋转变色 机制主动维持平衡性,即使在极端插入顺序下,树高仍被严格控制在 级别,因此在高频动态数据场景(如数据库索引、缓存实现)中具有不可替代的性能优势。

六、与AVL树的对比分析

红黑树与 AVL 树作为两种经典的自平衡二叉搜索树,在平衡机制、性能表现与工程应用上存在显著差异。本章将从平衡机制→性能指标→工程选择 的逻辑框架展开对比,揭示两者在设计哲学与实践价值上的核心区别。

(一)平衡机制:近似平衡与严格平衡的分野

红黑树与 AVL 树的本质差异源于平衡控制策略的不同。红黑树采用"颜色约束驱动的近似平衡" ,通过五条核心规则(如"从根到叶子的所有路径包含相同数量的黑色节点""不存在连续红色节点")将树高控制在 ≤ 2log(n+1) 的范围内,允许最长路径为最短路径的 2 倍,属于"弱平衡"设计。这种机制通过对节点颜色(红/黑)的管理实现"懒惰平衡",仅在必要时触发调整,避免过度维护。

AVL 树则采用"高度差驱动的严格平衡" ,要求任何节点的左右子树高度差(平衡因子)绝对值 ≤ 1 ,树高可被严格控制在 ≈ 1.44log(n+2) ,属于"强平衡"设计。这种机制通过实时计算并维护每个节点的平衡因子(左子树高度 - 右子树高度),确保树结构始终处于"极致矮胖"状态,但需付出更高的调整成本。

两种平衡机制的差异直接体现在插入操作的处理流程中:

cpp 复制代码
A[插入新节点] --> B{是否是AVL树?}
B -->|是| C[计算所有祖先的平衡因子]
C --> D{平衡因子绝对值>1?}
D -->|是| E[旋转调整]
D -->|否| F[结束]
B -->|否(红黑树)| G[标记新节点为红色]
G --> H{父节点是红色?}
H -->|是| I[检查叔叔节点颜色]
I -->|叔叔是红色| J[父/叔变黑,祖父变红,向上递归]
I -->|叔叔是黑色/空| K[旋转调整+颜色翻转]
H -->|否| F[结束]

从流程图可见,AVL 树插入后需回溯更新所有祖先节点的平衡因子 ,并可能触发多次旋转;而红黑树仅在父节点为红色时才需处理,且优先通过颜色调整(如父/叔节点变色)减少旋转操作,体现了"以颜色换旋转"的设计思想。

(二)性能指标:动态操作效率与空间开销的权衡

2.1 平衡维护成本:旋转次数的数量级差异

红黑树在动态操作(插入/删除)中表现出显著的效率优势。插入操作最多仅需 2 次旋转 (如插入修复中的"单旋+变色"或"双旋+变色"),删除操作旋转次数同样为常数级 O(1)。这种低调整成本源于其"近似平衡"的特性------允许树结构在一定范围内波动,仅在突破颜色规则时触发最小化调整。

相比之下,AVL 树为维持严格平衡,插入/删除后可能需要多次递归旋转 。例如,删除一个节点可能导致祖先节点的平衡因子连锁失衡,需从叶子到根节点逐层调整,最坏情况下旋转次数达 O(log n)。这种高频旋转使其在动态数据场景下性能劣势明显。

2.2 空间开销:1 位 vs 多位的存储成本

红黑树的空间开销极低,仅需为每个节点额外存储 1 位颜色标记 (红/黑),可通过节点结构中的空闲位(如指针未使用的最低位)实现,几乎不增加存储负担。

AVL 树则需为每个节点存储平衡因子 (通常为 2-3 位,表示 -1、0、1 三种状态)或直接存储子树高度(整数),空间开销显著高于红黑树。在大规模数据场景下(如千万级节点),这种差异可能影响内存利用率。

2.3 时间复杂度:理论同阶,实践分化

尽管两种树的查找、插入、删除操作理论时间复杂度均为 O(log n) ,但实际性能因树高和调整成本不同而分化:

查询性能 :AVL 树因严格平衡导致树高更矮(约 1.44log n vs 红黑树 2log n),单次查询平均速度略快。

插入/删除性能 :红黑树因旋转次数少、调整成本低,在动态操作中表现更优,尤其在高频更新场景下(如每秒数万次插入删除),性能优势可达数倍。

(三)工程选择:场景适配与设计哲学的落地

红黑树与 AVL 树的工程选择本质是**"动态效率"与"静态查询性能"的权衡** 。以下为典型场景的决策依据:

3.1 红黑树:动态数据场景的首选

红黑树凭借低调整成本和稳定的动态性能,广泛应用于插入/删除频繁的场景

STL 容器 :C++ STL 中的 std::map、std::set 均采用红黑树实现,因其能高效支持频繁的元素插入与删除,满足关联容器的性能需求。

实时系统 :如进程调度队列(Linux 的 CFS 调度器)、实时排行榜,需快速响应动态数据变化,红黑树的 O(1) 旋转特性可保障低延迟。

缓存实现 :如 LRU 缓存的底层结构,需频繁淘汰旧数据并插入新数据,红黑树的动态调整能力可降低维护成本。

3.2 AVL 树:静态查询场景的优化选择

AVL 树则适用于查询远多于更新 的静态或准静态数据场景:

字典库与索引 :如单词查找树、静态数据库索引,数据一旦构建后极少修改,AVL 树的严格平衡可确保最短查询路径,提升检索速度。

科学计算 :在数值分析或仿真中,需对固定数据集进行高频查询(如查找特定条件的样本),AVL 树的矮树高可减少比较次数。

核心结论 :红黑树是"性能与实现复杂度的折中",通过牺牲极致查找性能换取更低的插入/删除开销;AVL 树则追求"查询性能最大化",适合数据静态、查询密集的场景。工程选择时需优先评估操作频率(查询 vs 插入/删除)与数据动态性,而非单纯比较理论复杂度。

(四)对比总结表

|----------|--------------------------|------------------------|
| 对比维度 | 红黑树 | AVL 树 |
| 平衡机制 | 颜色约束(红/黑)+ 路径黑色节点数限制,弱平衡 | 平衡因子(左右子树高度差 ≤ 1),严格平衡 |
| 树高上限 | 2log(n+1) | 1.44log(n+2) - 1.328 |
| 旋转次数 | 插入/删除 ≤ 2 次(O(1)) | 插入/删除可能多次(O(log n)) |
| 空间开销 | 1 位(颜色标记) | 2-3 位(平衡因子)或整数(子树高度) |
| 适用场景 | 插入/删除频繁(动态数据) | 查询频繁(静态数据) |

七、红黑树的工程应用案

红黑树作为一种自平衡二叉搜索树,凭借其 O(log n) 的插入/删除/查找复杂度中序遍历有序性 的核心特性,在操作系统、编程语言标准库、数据库等关键领域得到广泛应用。以下从具体场景出发,剖析其技术选型逻辑与实现细节。

(一)编程语言标准库:有序容器的底层支柱

数据结构特性 :红黑树的中序遍历可生成有序序列,支持范围查询(如 [a, b] 区间数据获取)和动态维护有序集合,且最坏情况下仍保持 O(log n) 操作效率。

场景需求 :标准库需提供支持有序操作的容器(如键值对映射、无重复元素集合),同时满足频繁插入/删除后的性能稳定性。

实现细节

C++ STL :std::map、std::set 等容器底层采用红黑树变体实现,通过泛型节点(存储 key 或 pair<key, value>)和比较仿函数(Compare)适配不同数据类型。例如 std::map 的 lower_bound() 和 upper_bound() 方法,利用红黑树的有序性实现 O(log n) 范围查询,而哈希表(如 std::unordered_map)虽平均查询更快,但无法支持此类有序操作。

Java 集合框架 :TreeMap 和 TreeSet 基于红黑树实现,通过 Comparator 接口定义排序规则,支持 subMap()(范围子映射)和 descendingKeySet()(逆序遍历)等操作,其内部通过红黑树的旋转与着色维持平衡,确保 10 万级数据量下插入性能稳定在微秒级。

技术选型对比 :红黑树在标准库中替代哈希表的核心原因在于 有序性刚需 。例如数据库查询结果排序、日志按时间戳过滤等场景,需频繁使用 ORDER BY 或范围查询,此时红黑树的中序遍历有序性可直接满足需求,而哈希表需额外 O(n log n) 排序开销。

(二)Linux 内核 CFS 调度器:进程调度的效率引擎

数据结构特性 :红黑树的 findMin 操作可在 O(log n) 时间内定位最小节点,且插入/删除操作不破坏树的平衡性,适合动态更新的有序集合。

场景需求 :完全公平调度器(CFS)需按进程虚拟运行时间(vruntime)排序,快速选择下一个运行进程,同时支持进程创建/退出时的动态调整。

实现细节

内核实现 :CFS 调度器将可运行进程组织为红黑树,节点存储进程控制块(task_struct),键值为 vruntime。调度时通过 rb_first()(即 findMin 操作)定位 vruntime 最小的进程,确保每个进程获得公平的 CPU 时间片。插入(进程唤醒)和删除(进程阻塞)操作均为 O(log n),相比早期 O(n) 遍历的调度算法,在 1000+ 并发进程场景下响应延迟降低 90% 以上 。

关键结构体 :内核中红黑树节点定义为 struct rb_node { unsigned long __rb_parent_color; struct rb_node *rb_right; struct rb_node *rb_left; };,其中 __rb_parent_color 字段复用存储父节点指针与节点颜色(红/黑),通过位运算优化内存占用 。

(三)Nginx 定时器:高效事件驱动的核心组件

数据结构特性 :红黑树支持动态事件的快速插入、删除和极值查询,且节点删除操作(尤其是中间节点)效率优于最小堆(最小堆删除非根节点需 O(n) 查找)。

场景需求 :Nginx 作为事件驱动服务器,需管理大量连接超时事件(如 HTTP 连接 60s 无活动关闭),要求毫秒级插入/删除和最近事件查询。

实现细节

定时器管理 :Nginx 通过 ngx_rbtree_t 结构体实现红黑树,节点存储事件的超时时间戳(key)和回调函数。每次事件循环中,通过 ngx_rbtree_min() 找到最小时间戳节点,判断是否触发超时事件;新增事件时执行 ngx_rbtree_insert(),连接关闭时执行 ngx_rbtree_delete(),三者均为 O(log n) 复杂度。在 10 万级并发连接场景下,红黑树相比链表实现(O(n) 遍历)将定时器检查耗时从秒级降至微秒级 。

性能优势 :对比最小堆,红黑树在事件频繁取消(如连接提前关闭)场景下更高效。例如某连接建立后 10s 内主动关闭,红黑树可直接定位并删除节点(O(log n)),而最小堆需先线性扫描找到节点(O(n))再调整堆结构,在高并发下会成为性能瓶颈。

(四)数据库与缓存:索引与排序的底层支撑

数据结构特性 :红黑树可作为辅助索引结构,支持有序数据的快速定位与范围扫描,且内存占用低于 B+ 树(无页表结构)。

场景需求 :数据库需对中间结果排序(如 ORDER BY)、缓存系统需维护有序键值对(如按访问频率排序的淘汰策略)。

实现细节

MySQL 排序优化 :当 ORDER BY 操作无法利用索引时,MySQL 若内存充足会使用红黑树(而非快速排序)对结果集排序。红黑树通过动态插入元素维持有序,避免快速排序的 O(n log n) 一次性开销,尤其适合流式数据场景(如边查询边排序)。

Redis 早期 ZSET :Redis 有序集合(ZSET)早期采用红黑树实现,键为分数(score),值为成员(member),支持 ZRANGE(范围查询)和 ZADD(插入)操作。虽然后续因内存优化改为跳跃表,但红黑树的 O(log n) 复杂度仍为其提供了设计参考 。

工程权衡 :红黑树在数据库中多作为内存级索引或临时排序结构,而磁盘级索引更倾向 B+ 树(优化磁盘 IO)。这种分层选型体现了红黑树在 内存密集型有序场景 下的高效性。

总结:红黑树的技术适配场景

红黑树的工程价值集中体现于 "动态有序集合 + 频繁更新" 场景:其 O(log n) 复杂度平衡了性能与实现难度,有序性满足范围查询需求,自平衡特性确保极端情况下的稳定性。从编程语言基础组件到操作系统内核,从 Web 服务器到数据库,红黑树以其独特的特性成为中间件与系统软件的关键数据结构基石。

八、实现难点与优化建议

红黑树的工程实现需在严格遵循其五大性质的基础上,处理复杂的指针操作与边界条件,同时兼顾性能与空间效率。以下从实现难点剖析、优化策略及调试方法三个维度展开分析。

(一)实现难点剖析

旋转操作中的指针维护疏漏 是红黑树实现的核心易错点。以左旋操作为例,其本质是调整节点间的父子关系与平衡因子,但实际编码中易忽略次级节点的指针更新。例如,当对节点 x 执行左旋时,需将 x 的右孩子 y 提升为新的父节点,此时除需更新 x 与 y 的直接父子指针外,必须同步修正 y 的左孩子(原 x 的右子树左分支)的 parent 指针,即执行 y->left->parent = x。若漏写此步骤,会导致该节点的 parent 指针仍指向 y,后续对该节点的访问(如删除或查找)将出现逻辑错误,破坏树的完整性。

边界条件处理复杂 是另一突出难点。传统实现中,叶子节点的子节点需用 nullptr 表示,导致插入、删除时需频繁判断节点是否为 nullptr,增加代码复杂度。采用**哨兵节点(nil 节点)** 可有效简化这一问题:将所有叶子节点的子节点统一指向 nil,并将 nil 节点的 parent、left、right 指针均指向自身,颜色设为黑色。此举可将边界条件转化为普通节点处理,例如判断节点是否为叶子节点时,直接检查其孩子是否为 nil,无需额外的 nullptr 判断逻辑,降低漏判风险。

(二)优化建议

空间优化方面 ,可借鉴 STL 源码的设计思路。红黑树节点的颜色属性传统上通过枚举类型(如 enum Color { RED, BLACK })表示,通常占用 4 字节(取决于编译器实现)。而 STL 中采用 bool 类型存储颜色(true 表示红色,false 表示黑色),仅占用 1 字节,在大规模节点场景下可显著节省内存开销。例如,对于包含 100 万个节点的红黑树,采用 bool 类型可减少 3MB 内存占用(按每个节点节省 3 字节计算)。

性能优化方面 ,需关注递归遍历的潜在瓶颈。以范围查询函数 countRangeHelper 为例,递归实现虽代码简洁,但在树深度较大时(如接近最坏情况的 O(n) 深度),可能导致栈溢出并增加函数调用开销。建议将其重构为非递归遍历 ,通过显式栈或队列模拟递归过程。例如,使用栈实现中序遍历:初始化时压入左子树所有节点,弹出节点时判断是否在查询范围内,再压入右子树所有节点。非递归实现可避免栈溢出风险,且在实际测试中,对深度为 1000 的红黑树执行范围查询时,性能提升约 15%~20%。

(三)工程实现与调试方法

严格遵循性质约束 是红黑树正确实现的前提。插入或删除操作后,需通过旋转与变色恢复五大性质,任何一步颜色判断或旋转顺序错误均可能导致树失衡。例如,插入红色节点后若父节点为红色,需根据叔叔节点颜色执行不同修复逻辑:若叔叔为黑色,需执行旋转+变色;若叔叔为红色,则仅需变色。若混淆这两种场景,会导致连续红节点或黑高不一致。

自动化性质检查 是高效调试的关键。可实现 checkProperties 函数对树的合法性进行全面校验,核心检查项包括:

根节点黑色性 :确保根节点始终为黑色;

红节点子节点黑色性 :通过 checkRedParentProperty 函数递归检测所有红色节点的子节点是否为黑色,避免连续红节点;

黑高一致性 :从根节点到所有叶子节点的黑色节点数量是否相同。

调试建议 :在开发阶段,可在每次插入、删除操作后调用 checkProperties 函数,若触发断言则定位问题节点。例如,当 checkRedParentProperty 检测到连续红节点时,可通过打印节点路径(如 x->parent->value -> x->value)快速定位违规节点,回溯操作日志排查颜色更新或旋转逻辑错误。

综上,红黑树的实现需在细节处理上保持严谨,通过哨兵节点简化边界条件,结合空间与性能优化策略,并依托自动化性质检查构建可靠的调试机制,才能在工程实践中确保其高效与稳定。

九、总结

红黑树是一种高效的自平衡二叉搜索树,通过颜色约束和旋转操作维持近似平衡,确保最坏情况下仍保持O(logn)的时间复杂度。其核心特性包括:

(1)节点为红/黑色;

(2)根和叶子节点为黑色;

(3)红色节点不能相邻;

(4)所有路径黑高相同。

与AVL树相比,红黑树插入/删除效率更高(旋转次数少),适合动态数据场景,广泛应用于C++ STL、Linux进程调度等系统。实现时需注意指针维护和边界条件处理,采用哨兵节点简化逻辑,并通过自动化性质检查确保正确性。红黑树在动态有序集合管理上展现出卓越性能,是平衡效率与复杂度的经典数据结构。

相关推荐
西猫雷婶3 小时前
random.shuffle()函数随机打乱数据
开发语言·pytorch·python·学习·算法·线性回归·numpy
学编程的小鬼3 小时前
SpringBoot 自动装配原理剖析
java·spring boot·后端
小李独爱秋3 小时前
机器学习中的聚类理论与K-means算法详解
人工智能·算法·机器学习·支持向量机·kmeans·聚类
liu****3 小时前
负载均衡式的在线OJ项目编写(六)
运维·c++·负载均衡·个人开发
♛小小小让让3 小时前
RabbitMQ (二)参数
笔记·python·rabbitmq
fly-phantomWing3 小时前
在命令提示符页面中用pip命令行安装Python第三方库的详细步骤
开发语言·python·pip
青草地溪水旁3 小时前
设计模式(C++)详解——迭代器模式(3)
c++·设计模式·迭代器模式
奔跑吧邓邓子4 小时前
【C++实战㊺】解锁C++代理模式:从理论到实战的深度剖析
c++·实战·代理模式
@@神农4 小时前
maven的概述以及在mac安装配置
java·macos·maven