《算法导论》第 13 章 - 红黑树

红黑树是一种自平衡的二叉搜索树,它通过一系列规则保证树的高度始终维持在 O (log n) 级别,从而确保插入、删除、查找等操作的时间复杂度均为 O (log n)。本文将详细解析红黑树的原理、操作及实现,附带完整可运行的 C++ 代码。

思维导图

13.1 红黑树的性质

红黑树是满足以下5 个性质的二叉搜索树:

  1. 每个节点要么是红色,要么是黑色
  2. 根节点是黑色
  3. 所有叶节点(NIL 节点)是黑色(注:叶节点指没有子节点的节点,通常用一个哨兵节点表示)
  4. 如果一个节点是红色,则它的两个子节点都是黑色(即不存在连续的红色节点)
  5. 从任意节点到其所有后代叶节点的路径中,包含相同数量的黑色节点(黑高相同)

这些性质共同保证了红黑树的高度不会超过 2log (n+1),从而实现了自平衡。

红黑树结构示意图

复制代码
        黑
      /   \
     红    红
    / \   / \
   黑 黑 黑 黑
  /
 红
/ \
黑 黑

上图中,所有路径的黑节点数均为 2(不含叶节点),且无连续红节点,满足红黑树性质。

13.2 旋转

旋转是红黑树维持平衡的核心操作,分为左旋右旋 ,其目的是改变树的结构而不破坏二叉搜索树的性质(即左子树节点值≤父节点值≤右子树节点值)。

左旋流程图

旋转代码实现

cpp 复制代码
#include <iostream>
using namespace std;

// 节点颜色定义
enum Color { RED, BLACK };

// 红黑树节点结构
struct Node {
    int data;       // 节点值
    Color color;    // 节点颜色
    Node *left, *right, *parent;  // 左子、右子、父节点

    // 构造函数
    Node(int val) : data(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};

// 红黑树类
class RedBlackTree {
private:
    Node* root;
    Node* nil;  // 哨兵节点(所有叶节点的替代,简化边界处理)

    // 左旋操作(x为要旋转的节点)
    void leftRotate(Node* x) {
        Node* y = x->right;  // y是x的右子节点
        x->right = y->left;  // 将y的左子树转为x的右子树

        if (y->left != nil) {
            y->left->parent = x;  // 若y有左子,更新其父节点为x
        }

        y->parent = x->parent;  // y的父节点更新为x的父节点

        // 处理x的父节点指向
        if (x->parent == nil) {
            root = y;  // 若x是根节点,则y成为新根
        } else if (x == x->parent->left) {
            x->parent->left = y;  // 若x是左子,则y成为其父的左子
        } else {
            x->parent->right = y;  // 若x是右子,则y成为其父的右子
        }

        y->left = x;  // x成为y的左子节点
        x->parent = y;  // x的父节点更新为y
    }

    // 右旋操作(y为要旋转的节点)
    void rightRotate(Node* y) {
        Node* x = y->left;  // x是y的左子节点
        y->left = x->right;  // 将x的右子树转为y的左子树

        if (x->right != nil) {
            x->right->parent = y;  // 若x有右子,更新其父节点为y
        }

        x->parent = y->parent;  // x的父节点更新为y的父节点

        // 处理y的父节点指向
        if (y->parent == nil) {
            root = x;  // 若y是根节点,则x成为新根
        } else if (y == y->parent->right) {
            y->parent->right = x;  // 若y是右子,则x成为其父的右子
        } else {
            y->parent->left = x;  // 若y是左子,则x成为其父的左子
        }

        x->right = y;  // y成为x的右子节点
        y->parent = x;  // y的父节点更新为x
    }

    // 中序遍历(用于打印树结构)
    void inorderTraversal(Node* node) {
        if (node != nil) {
            inorderTraversal(node->left);
            cout << node->data << "(" << (node->color == RED ? "红" : "黑") << ") ";
            inorderTraversal(node->right);
        }
    }

public:
    // 构造函数初始化
    RedBlackTree() {
        nil = new Node(0);
        nil->color = BLACK;  // 哨兵节点为黑色
        nil->left = nil;     // 哨兵的子节点指向自己,避免空指针
        nil->right = nil;
        root = nil;  // 初始根节点为哨兵
    }

    // 插入节点(简化版,仅用于测试旋转)
    void insert(int val) {
        Node* z = new Node(val);
        Node* y = nil;
        Node* x = root;

        // 找到插入位置
        while (x != nil) {
            y = x;
            if (z->data < x->data) {
                x = x->left;
            } else {
                x = x->right;
            }
        }

        z->parent = y;
        if (y == nil) {
            root = z;
        } else if (z->data < y->data) {
            y->left = z;
        } else {
            y->right = z;
        }

        z->left = nil;
        z->right = nil;
        z->color = RED;  // 新节点初始为红色
    }

    // 公开接口:执行左旋
    void performLeftRotate(int val) {
        Node* x = root;
        // 查找要旋转的节点
        while (x != nil && x->data != val) {
            if (val < x->data) {
                x = x->left;
            } else {
                x = x->right;
            }
        }
        if (x != nil) {
            leftRotate(x);
            cout << "对 " << val << " 执行左旋后: ";
            printTree();
        } else {
            cout << "未找到值为 " << val << " 的节点,无法左旋" << endl;
        }
    }

    // 公开接口:执行右旋
    void performRightRotate(int val) {
        Node* y = root;
        // 查找要旋转的节点
        while (y != nil && y->data != val) {
            if (val < y->data) {
                y = y->left;
            } else {
                y = y->right;
            }
        }
        if (y != nil) {
            rightRotate(y);
            cout << "对 " << val << " 执行右旋后: ";
            printTree();
        } else {
            cout << "未找到值为 " << val << " 的节点,无法右旋" << endl;
        }
    }

    // 打印树结构
    void printTree() {
        inorderTraversal(root);
        cout << endl;
    }
};

// 主函数:测试旋转功能
int main() {
    RedBlackTree tree;

    // 插入测试数据
    tree.insert(10);
    tree.insert(20);
    tree.insert(30);
    tree.insert(15);
    
    cout << "初始树结构: ";
    tree.printTree();

    // 测试左旋
    tree.performLeftRotate(10);  // 对10执行左旋

    // 测试右旋
    tree.performRightRotate(30); // 对30执行右旋

    return 0;  // 程序入口必须有返回值
}

左旋和右旋是对称操作,时间复杂度均为 O (1),仅改变指针指向而不修改节点值。

13.3 插入

红黑树的插入流程分为两步:二叉搜索树插入修复红黑树性质

插入步骤

  1. 按二叉搜索树规则插入新节点(初始颜色为红色,减少对黑高的影响)。

  2. 检查是否违反红黑树性质(若父节点为黑色则无问题;若父节点为红色则违反性质 4)。

  3. 通过重新染色旋转修复性质,分 3 种情形处理:

    • 情形 1:叔节点为红色 → 重新染色父、叔、祖父节点。
    • 情形 2:叔节点为黑色,且新节点是 "三角" 结构(父左子 + 新右子 或 父右子 + 新左子)→ 旋转转为情形 3。
    • 情形 3:叔节点为黑色,且新节点是 "直线" 结构(父左子 + 新左子 或 父右子 + 新右子)→ 旋转 + 染色修复。

插入修复

插入代码实现(续红黑树类)

cpp 复制代码
#include <iostream>
using namespace std;

// 节点颜色定义
enum Color { RED, BLACK };

// 红黑树节点结构
struct Node {
    int data;               // 节点值
    Color color;            // 节点颜色
    Node *left, *right, *parent;  // 左子、右子、父节点

    // 构造函数
    Node(int val) : data(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};

// 红黑树类
class RedBlackTree {
private:
    Node* root;
    Node* nil;  // 哨兵节点(所有叶节点的替代,简化边界处理)

    // 左旋操作(x为要旋转的节点)
    void leftRotate(Node* x) {
        Node* y = x->right;  // y是x的右子节点
        x->right = y->left;  // 将y的左子树转为x的右子树

        if (y->left != nil) {
            y->left->parent = x;  // 若y有左子,更新其父节点为x
        }

        y->parent = x->parent;  // y的父节点更新为x的父节点

        // 处理x的父节点指向
        if (x->parent == nil) {
            root = y;  // 若x是根节点,则y成为新根
        } else if (x == x->parent->left) {
            x->parent->left = y;  // 若x是左子,则y成为其父的左子
        } else {
            x->parent->right = y;  // 若x是右子,则y成为其父的右子
        }

        y->left = x;  // x成为y的左子节点
        x->parent = y;  // x的父节点更新为y
    }

    // 右旋操作(y为要旋转的节点)
    void rightRotate(Node* y) {
        Node* x = y->left;  // x是y的左子节点
        y->left = x->right;  // 将x的右子树转为y的左子树

        if (x->right != nil) {
            x->right->parent = y;  // 若x有右子,更新其父节点为y
        }

        x->parent = y->parent;  // x的父节点更新为y的父节点

        // 处理y的父节点指向
        if (y->parent == nil) {
            root = x;  // 若y是根节点,则x成为新根
        } else if (y == y->parent->right) {
            y->parent->right = x;  // 若y是右子,则x成为其父的右子
        } else {
            y->parent->left = x;  // 若y是左子,则x成为其父的左子
        }

        x->right = y;  // y成为x的右子节点
        y->parent = x;  // y的父节点更新为x
    }

    // 插入后修复红黑树性质
    void insertFixup(Node* z) {
        // 当父节点为红色时(违反性质4:红色节点的子节点必须是黑色)
        while (z->parent->color == RED) {
            // 父节点是祖父节点的左子节点
            if (z->parent == z->parent->parent->left) {  
                Node* y = z->parent->parent->right;  // 叔节点(祖父的右子)

                // 情形1:叔节点为红色
                if (y->color == RED) {
                    z->parent->color = BLACK;       // 父节点染黑
                    y->color = BLACK;               // 叔节点染黑
                    z->parent->parent->color = RED; // 祖父节点染红
                    z = z->parent->parent;          // 以祖父为新节点继续检查
                } 
                // 叔节点为黑色
                else {
                    // 情形2:叔节点为黑,且z是右子(三角结构)
                    if (z == z->parent->right) {
                        z = z->parent;  // 以父节点为基准
                        leftRotate(z);  // 左旋转为直线结构,转为情形3
                    }
                    // 情形3:叔节点为黑,且z是左子(直线结构)
                    z->parent->color = BLACK;       // 父节点染黑
                    z->parent->parent->color = RED; // 祖父节点染红
                    rightRotate(z->parent->parent); // 右旋祖父节点
                }
            } 
            // 父节点是祖父节点的右子节点(对称逻辑)
            else {  
                Node* y = z->parent->parent->left;  // 叔节点(祖父的左子)

                // 情形1:叔节点为红色
                if (y->color == RED) {
                    z->parent->color = BLACK;
                    y->color = BLACK;
                    z->parent->parent->color = RED;
                    z = z->parent->parent;
                } 
                // 叔节点为黑色
                else {
                    // 情形2:叔节点为黑,且z是左子(三角结构)
                    if (z == z->parent->left) {
                        z = z->parent;
                        rightRotate(z);  // 右旋转为直线结构,转为情形3
                    }
                    // 情形3:叔节点为黑,且z是右子(直线结构)
                    z->parent->color = BLACK;
                    z->parent->parent->color = RED;
                    leftRotate(z->parent->parent);
                }
            }
        }
        root->color = BLACK;  // 确保根节点为黑色(修复可能被破坏的性质2)
    }

    // 中序遍历(用于打印树结构,按值升序输出)
    void inorderTraversal(Node* node) {
        if (node != nil) {
            inorderTraversal(node->left);
            cout << node->data << "(" << (node->color == RED ? "红" : "黑") << ") ";
            inorderTraversal(node->right);
        }
    }

public:
    // 构造函数初始化
    RedBlackTree() {
        nil = new Node(0);
        nil->color = BLACK;  // 哨兵节点为黑色
        nil->left = nil;     // 哨兵的子节点指向自己,避免空指针
        nil->right = nil;
        root = nil;  // 初始根节点为哨兵
    }

    // 插入节点
    void insert(int val) {
        Node* z = new Node(val);
        Node* y = nil;  // y记录x的父节点
        Node* x = root;

        // 找到插入位置(类似二叉搜索树)
        while (x != nil) {
            y = x;
            if (z->data < x->data) {
                x = x->left;
            } else {
                x = x->right;
            }
        }

        z->parent = y;  // z的父节点设为y
        if (y == nil) {
            root = z;  // 树为空,z成为根节点
        } else if (z->data < y->data) {
            y->left = z;  // z成为y的左子
        } else {
            y->right = z;  // z成为y的右子
        }

        z->left = nil;   // 左右子节点设为哨兵
        z->right = nil;
        z->color = RED;  // 新节点初始为红色(减少对黑高的影响)

        insertFixup(z);  // 修复红黑树性质
    }

    // 打印树结构
    void printTree() {
        inorderTraversal(root);
        cout << endl;
    }
};

// 测试红黑树插入功能
int main() {
    RedBlackTree tree;

    // 插入测试数据
    int values[] = {10, 20, 5, 15, 30, 25, 35};
    int n = sizeof(values) / sizeof(values[0]);

    for (int i = 0; i < n; i++) {
        tree.insert(values[i]);
        cout << "插入 " << values[i] << " 后,树结构为: ";
        tree.printTree();
    }

    return 0;
}

13.4 删除

红黑树的删除是最复杂的操作,流程如下:

删除步骤

  1. 按二叉搜索树规则删除节点:
    • 若节点有 0 个或 1 个子节点,直接删除并替换。
    • 若节点有 2 个子节点,用后继节点(右子树最小节点)替换,再删除后继节点。
  2. 记录被删除节点的颜色(若为黑色则可能破坏性质 5)和替换节点。
  3. 若删除的是黑色节点,通过修复函数处理 "双黑" 问题(因黑高减少导致的性质 5 破坏)。

删除修复核心逻辑

删除黑色节点后,其位置会产生 "双黑" 标记(可理解为需要额外的黑色补偿)。修复函数通过以下方式处理:

  • 若兄弟节点为红色 → 旋转 + 染色转为兄弟节点为黑色的情形。
  • 若兄弟节点为黑色:
    • 兄弟节点的子节点均为黑色 → 兄弟染红,向上传递双黑标记。
    • 兄弟节点的左子为红(右子为黑)→ 旋转 + 染色转为右子为红的情形。
    • 兄弟节点的右子为红 → 旋转 + 染色修复双黑。

删除代码实现(续红黑树类)

cpp 复制代码
#include <iostream>
using namespace std;

// 节点颜色定义
enum Color { RED, BLACK };

// 红黑树节点结构
struct Node {
    int data;               // 节点值
    Color color;            // 节点颜色
    Node *left, *right, *parent;  // 左子、右子、父节点

    // 构造函数
    Node(int val) : data(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};

// 红黑树类
class RedBlackTree {
private:
    Node* root;
    Node* nil;  // 哨兵节点(所有叶节点的替代,简化边界处理)

    // 左旋操作
    void leftRotate(Node* x) {
        Node* y = x->right;  // y是x的右子节点
        x->right = y->left;  // 将y的左子树转为x的右子树

        if (y->left != nil) {
            y->left->parent = x;  // 若y有左子,更新其父节点为x
        }

        y->parent = x->parent;  // y的父节点更新为x的父节点

        // 处理x的父节点指向
        if (x->parent == nil) {
            root = y;  // 若x是根节点,则y成为新根
        } else if (x == x->parent->left) {
            x->parent->left = y;  // 若x是左子,则y成为其父的左子
        } else {
            x->parent->right = y;  // 若x是右子,则y成为其父的右子
        }

        y->left = x;  // x成为y的左子节点
        x->parent = y;  // x的父节点更新为y
    }

    // 右旋操作
    void rightRotate(Node* y) {
        Node* x = y->left;  // x是y的左子节点
        y->left = x->right;  // 将x的右子树转为y的左子树

        if (x->right != nil) {
            x->right->parent = y;  // 若x有右子,更新其父节点为y
        }

        x->parent = y->parent;  // x的父节点更新为y的父节点

        // 处理y的父节点指向
        if (y->parent == nil) {
            root = x;  // 若y是根节点,则x成为新根
        } else if (y == y->parent->right) {
            y->parent->right = x;  // 若y是右子,则x成为其父的右子
        } else {
            y->parent->left = x;  // 若y是左子,则x成为其父的左子
        }

        x->right = y;  // y成为x的右子节点
        y->parent = x;  // y的父节点更新为x
    }

    // 插入后修复红黑树性质(完整实现才能正常测试删除)
    void insertFixup(Node* z) {
        while (z->parent->color == RED) {
            if (z->parent == z->parent->parent->left) {
                Node* y = z->parent->parent->right;
                if (y->color == RED) {
                    z->parent->color = BLACK;
                    y->color = BLACK;
                    z->parent->parent->color = RED;
                    z = z->parent->parent;
                } else {
                    if (z == z->parent->right) {
                        z = z->parent;
                        leftRotate(z);
                    }
                    z->parent->color = BLACK;
                    z->parent->parent->color = RED;
                    rightRotate(z->parent->parent);
                }
            } else {
                Node* y = z->parent->parent->left;
                if (y->color == RED) {
                    z->parent->color = BLACK;
                    y->color = BLACK;
                    z->parent->parent->color = RED;
                    z = z->parent->parent;
                } else {
                    if (z == z->parent->left) {
                        z = z->parent;
                        rightRotate(z);
                    }
                    z->parent->color = BLACK;
                    z->parent->parent->color = RED;
                    leftRotate(z->parent->parent);
                }
            }
        }
        root->color = BLACK;
    }

    // 移植节点(辅助删除操作)
    void transplant(Node* u, Node* 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;
    }

    // 查找最小节点(用于找后继)
    Node* minimum(Node* x) {
        while (x->left != nil) {
            x = x->left;
        }
        return x;
    }

    // 删除后修复红黑树性质
    void deleteFixup(Node* x) {
        // 当x不是根节点且为黑色时需要修复(双黑问题)
        while (x != root && x->color == BLACK) {
            // x是左子节点的情况
            if (x == x->parent->left) {  
                Node* w = x->parent->right;  // 兄弟节点

                // 情形1:兄弟节点为红色
                if (w->color == RED) {
                    w->color = BLACK;         // 兄弟染黑
                    x->parent->color = RED;   // 父节点染红
                    leftRotate(x->parent);    // 左旋父节点
                    w = x->parent->right;     // 更新兄弟节点
                }

                // 情形2:兄弟节点的两个子节点均为黑色
                if (w->left->color == BLACK && w->right->color == BLACK) {
                    w->color = RED;           // 兄弟染红
                    x = x->parent;            // 向上传递双黑标记
                } else {
                    // 情形3:兄弟左子为红,右子为黑
                    if (w->right->color == BLACK) {
                        w->left->color = BLACK;  // 兄弟左子染黑
                        w->color = RED;          // 兄弟染红
                        rightRotate(w);          // 右旋兄弟
                        w = x->parent->right;    // 更新兄弟节点
                    }
                    // 情形4:兄弟右子为红
                    w->color = x->parent->color;  // 兄弟继承父节点颜色
                    x->parent->color = BLACK;     // 父节点染黑
                    w->right->color = BLACK;      // 兄弟右子染黑
                    leftRotate(x->parent);        // 左旋父节点
                    x = root;                     // 退出循环
                }
            } else {  // x是右子节点的情况(对称逻辑)
                Node* w = x->parent->left;  // 兄弟节点

                // 情形1:兄弟节点为红色
                if (w->color == RED) {
                    w->color = BLACK;
                    x->parent->color = RED;
                    rightRotate(x->parent);
                    w = x->parent->left;
                }

                // 情形2:兄弟节点的两个子节点均为黑色
                if (w->right->color == BLACK && w->left->color == BLACK) {
                    w->color = RED;
                    x = x->parent;
                } else {
                    // 情形3:兄弟右子为红,左子为黑
                    if (w->left->color == BLACK) {
                        w->right->color = BLACK;
                        w->color = RED;
                        leftRotate(w);
                        w = x->parent->left;
                    }
                    // 情形4:兄弟左子为红
                    w->color = x->parent->color;
                    x->parent->color = BLACK;
                    w->left->color = BLACK;
                    rightRotate(x->parent);
                    x = root;  // 退出循环
                }
            }
        }
        x->color = BLACK;  // 确保x为黑色,解决双黑问题
    }

    // 中序遍历(用于打印树结构)
    void inorderTraversal(Node* node) {
        if (node != nil) {
            inorderTraversal(node->left);
            cout << node->data << "(" << (node->color == RED ? "红" : "黑") << ") ";
            inorderTraversal(node->right);
        }
    }

public:
    // 构造函数初始化
    RedBlackTree() {
        nil = new Node(0);
        nil->color = BLACK;  // 哨兵节点为黑色
        nil->left = nil;     // 哨兵的子节点指向自己,避免空指针
        nil->right = nil;
        root = nil;  // 初始根节点为哨兵
    }

    // 插入节点(用于构建测试树)
    void insert(int val) {
        Node* z = new Node(val);
        Node* y = nil;
        Node* x = root;

        while (x != nil) {
            y = x;
            if (z->data < x->data) {
                x = x->left;
            } else {
                x = x->right;
            }
        }

        z->parent = y;
        if (y == nil) {
            root = z;
        } else if (z->data < y->data) {
            y->left = z;
        } else {
            y->right = z;
        }

        z->left = nil;
        z->right = nil;
        z->color = RED;

        insertFixup(z);
    }

    // 删除节点
    void deleteNode(int val) {
        Node* z = root;
        Node* y = nil;
        Node* x = nil;

        // 查找值为val的节点
        while (z != nil && z->data != val) {
            if (val < z->data) {
                z = z->left;
            } else {
                z = z->right;
            }
        }
        if (z == nil) {
            cout << "值 " << val << " 不在树中,无法删除" << endl;
            return;
        }

        y = z;
        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;
        }

        delete z;  // 释放被删除节点内存

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

    // 查找节点(用于验证)
    bool search(int val) {
        Node* x = root;
        while (x != nil) {
            if (x->data == val) {
                return true;
            } else if (val < x->data) {
                x = x->left;
            } else {
                x = x->right;
            }
        }
        return false;
    }

    // 打印树结构
    void printTree() {
        inorderTraversal(root);
        cout << endl;
    }
};

// 测试红黑树删除功能
int main() {
    RedBlackTree tree;

    // 插入测试数据
    int values[] = {10, 20, 5, 15, 30, 25, 35};
    int n = sizeof(values) / sizeof(values[0]);

    cout << "=== 插入节点过程 ===" << endl;
    for (int i = 0; i < n; i++) {
        tree.insert(values[i]);
        cout << "插入 " << values[i] << " 后: ";
        tree.printTree();
    }

    // 测试删除操作
    cout << "\n=== 删除节点过程 ===" << endl;
    int deleteValues[] = {20, 10, 30};
    for (int val : deleteValues) {
        if (tree.search(val)) {
            tree.deleteNode(val);
            cout << "删除 " << val << " 后: ";
            tree.printTree();
        } else {
            cout << "删除 " << val << " 失败:节点不存在" << endl;
        }
    }

    // 测试删除不存在的节点
    tree.deleteNode(100);

    return 0;
}

综合案例:红黑树实现有序映射

以下是一个完整的红黑树应用案例,实现了有序映射的插入、删除、查找和遍历功能:

cpp 复制代码
#include <iostream>
using namespace std;

// 节点颜色定义
enum Color { RED, BLACK };

// 红黑树节点结构
struct Node {
    int data;               // 节点值
    Color color;            // 节点颜色
    Node *left, *right, *parent;  // 左子、右子、父节点

    // 构造函数
    Node(int val) : data(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};

// 红黑树类
class RedBlackTree {
private:
    Node* root;
    Node* nil;  // 哨兵节点(简化边界处理)

    // 左旋操作
    void leftRotate(Node* x) {
        Node* 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;
    }

    // 右旋操作
    void rightRotate(Node* y) {
        Node* 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->right) {
            y->parent->right = x;
        } else {
            y->parent->left = x;
        }

        x->right = y;
        y->parent = x;
    }

    // 插入修复
    void insertFixup(Node* z) {
        while (z->parent->color == RED) {
            if (z->parent == z->parent->parent->left) {
                Node* y = z->parent->parent->right;
                if (y->color == RED) {
                    z->parent->color = BLACK;
                    y->color = BLACK;
                    z->parent->parent->color = RED;
                    z = z->parent->parent;
                } else {
                    if (z == z->parent->right) {
                        z = z->parent;
                        leftRotate(z);
                    }
                    z->parent->color = BLACK;
                    z->parent->parent->color = RED;
                    rightRotate(z->parent->parent);
                }
            } else {
                Node* y = z->parent->parent->left;
                if (y->color == RED) {
                    z->parent->color = BLACK;
                    y->color = BLACK;
                    z->parent->parent->color = RED;
                    z = z->parent->parent;
                } else {
                    if (z == z->parent->left) {
                        z = z->parent;
                        rightRotate(z);
                    }
                    z->parent->color = BLACK;
                    z->parent->parent->color = RED;
                    leftRotate(z->parent->parent);
                }
            }
        }
        root->color = BLACK;
    }

    // 移植节点(辅助删除)
    void transplant(Node* u, Node* 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;
    }

    // 查找最小节点(找后继)
    Node* minimum(Node* x) {
        while (x->left != nil) {
            x = x->left;
        }
        return x;
    }

    // 删除修复
    void deleteFixup(Node* x) {
        while (x != root && x->color == BLACK) {
            if (x == x->parent->left) {
                Node* w = x->parent->right;
                if (w->color == RED) {
                    w->color = BLACK;
                    x->parent->color = RED;
                    leftRotate(x->parent);
                    w = x->parent->right;
                }

                if (w->left->color == BLACK && w->right->color == BLACK) {
                    w->color = RED;
                    x = x->parent;
                } else {
                    if (w->right->color == BLACK) {
                        w->left->color = BLACK;
                        w->color = RED;
                        rightRotate(w);
                        w = x->parent->right;
                    }
                    w->color = x->parent->color;
                    x->parent->color = BLACK;
                    w->right->color = BLACK;
                    leftRotate(x->parent);
                    x = root;
                }
            } else {
                Node* w = x->parent->left;
                if (w->color == RED) {
                    w->color = BLACK;
                    x->parent->color = RED;
                    rightRotate(x->parent);
                    w = x->parent->left;
                }

                if (w->right->color == BLACK && w->left->color == BLACK) {
                    w->color = RED;
                    x = x->parent;
                } else {
                    if (w->left->color == BLACK) {
                        w->right->color = BLACK;
                        w->color = RED;
                        leftRotate(w);
                        w = x->parent->left;
                    }
                    w->color = x->parent->color;
                    x->parent->color = BLACK;
                    w->left->color = BLACK;
                    rightRotate(x->parent);
                    x = root;
                }
            }
        }
        x->color = BLACK;
    }

    // 中序遍历(内部实现)
    void inorderTraversal(Node* x) {
        if (x != nil) {
            inorderTraversal(x->left);
            cout << x->data << "(" << (x->color == RED ? "红" : "黑") << ") ";
            inorderTraversal(x->right);
        }
    }

public:
    // 构造函数
    RedBlackTree() {
        nil = new Node(0);
        nil->color = BLACK;
        nil->left = nil;
        nil->right = nil;
        root = nil;
    }

    // 插入节点
    void insert(int val) {
        Node* z = new Node(val);
        Node* y = nil;
        Node* x = root;

        while (x != nil) {
            y = x;
            if (z->data < x->data) {
                x = x->left;
            } else {
                x = x->right;
            }
        }

        z->parent = y;
        if (y == nil) {
            root = z;
        } else if (z->data < y->data) {
            y->left = z;
        } else {
            y->right = z;
        }

        z->left = nil;
        z->right = nil;
        z->color = RED;

        insertFixup(z);
    }

    // 删除节点
    void deleteNode(int val) {
        Node* z = root;
        while (z != nil && z->data != val) {
            if (val < z->data) {
                z = z->left;
            } else {
                z = z->right;
            }
        }

        if (z == nil) {
            cout << "值 " << val << " 不在树中,无法删除" << endl;
            return;
        }

        Node* y = z;
        Color yOriginalColor = y->color;
        Node* x = nil;

        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;
        }

        delete z;

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

    // 查找节点
    bool search(int val) {
        Node* x = root;
        while (x != nil) {
            if (x->data == val) {
                return true;  // 找到节点
            } else if (val < x->data) {
                x = x->left;  // 向左子树查找
            } else {
                x = x->right;  // 向右子树查找
            }
        }
        return false;  // 未找到节点
    }

    // 公开接口:打印树
    void printTree() {
        cout << "中序遍历(值+颜色):";
        inorderTraversal(root);
        cout << endl;
    }
};

// 测试代码
int main() {
    RedBlackTree tree;

    // 插入测试
    int nums[] = {10, 20, 5, 15, 30, 25};
    for (int num : nums) {
        tree.insert(num);
        cout << "插入 " << num << " 后:";
        tree.printTree();
    }

    // 查找测试
    int targets[] = {15, 22, 5, 30};
    for (int target : targets) {
        cout << "查找 " << target << ":" << (tree.search(target) ? "存在" : "不存在") << endl;
    }

    // 删除测试
    tree.deleteNode(20);
    cout << "删除 20 后:";
    tree.printTree();

    tree.deleteNode(10);
    cout << "删除 10 后:";
    tree.printTree();

    // 验证删除后的查找结果
    cout << "删除后查找 10:" << (tree.search(10) ? "存在" : "不存在") << endl;
    cout << "删除后查找 20:" << (tree.search(20) ? "存在" : "不存在") << endl;

    return 0;
}

输出结果示例

思考题

  1. 证明红黑树的高度不超过 2log (n+1)(提示:利用黑高和二叉树高度的关系)。
  2. 若将新插入节点初始颜色设为黑色,会对红黑树性质产生什么影响?修复成本如何变化?
  3. 设计一个算法,统计红黑树中红色节点的数量,要求时间复杂度 O (n)。
  4. 比较红黑树与 AVL 树的优缺点及适用场景。

本章注记

  • 红黑树由 Rudolf Bayer 于 1972 年发明,最初称为 "对称二叉 B 树",后由 Leo Guibas 和 Robert Sedgewick 简化并命名为红黑树。
  • 红黑树在工程中应用广泛:C++ STL 的std::mapstd::set、Java 的TreeMap、Linux 内核的进程调度、nginx 的定时器等均采用红黑树实现。
  • 红黑树的平衡策略是 "宽松平衡"(黑高平衡),相比 AVL 树的 "严格平衡"(高度差≤1),插入删除的旋转次数更少,适合频繁修改的场景。
  • 红黑树的哨兵节点(nil)是工程实现中的常用技巧,可简化边界条件判断(如避免空指针检查)。

说明

本文提供的红黑树代码已包含所有核心功能(插入、删除、查找、遍历),可直接编译运行。代码采用哨兵节点简化逻辑,所有操作均保证红黑树性质不被破坏,时间复杂度为 O (log n)。实际使用时可根据需求扩展(如泛型支持、自定义比较器等)。

相关推荐
laplaya4 分钟前
高性能分布式通信框架:eCAL 介绍与应用
c++·分布式
绕灵儿17 分钟前
C++ 部署LSTM(.onnx)
开发语言·c++·lstm
三次拒绝王俊凯3 小时前
用生活日常的案例来介绍“程序运行时,对函数的调用一般有两种形式:传值调用和引用调用 和 这两种调用有什么区别?
java·数据结构
qiuyunoqy3 小时前
蓝桥杯算法之搜索章 - 3
c++·算法·蓝桥杯·深度优先·dfs·剪枝
阿飞__3 小时前
Linux开发板(如RK3588)上打开摄像头设备并获取实时画面
c++·gstreamer
lifallen4 小时前
Kafka ISR机制和Raft区别:副本数优化的秘密
java·大数据·数据库·分布式·算法·kafka·apache
希望_睿智4 小时前
实战设计模式之代理模式
c++·设计模式·架构
m0_626535204 小时前
贪心算法学习 3 买卖股票的最佳时机 i ii
学习·算法·贪心算法
乌萨奇也要立志学C++4 小时前
【C++详解】AVL树深度剖析与模拟实现(单旋、双旋、平衡因⼦更新、平衡检测)
c++