当前位置: 首页 > news >正文

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

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

思维导图

13.1 红黑树的性质

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

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

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

红黑树结构示意图

        黑/   \红    红/ \   / \黑 黑 黑 黑/红
/ \
黑 黑

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

13.2 旋转

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

左旋流程图

旋转代码实现

#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:叔节点为黑色,且新节点是 "直线" 结构(父左子 + 新左子 或 父右子 + 新右子)→ 旋转 + 染色修复。

插入修复

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

#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的父节点设为yif (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 破坏)。

删除修复核心逻辑

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

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

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

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

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

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

#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)。实际使用时可根据需求扩展(如泛型支持、自定义比较器等)。

http://www.dtcms.com/a/322946.html

相关文章:

  • 基于Dify实现对Excel的数据分析--动态配置图表
  • pytorch+tensorboard+可视化CNN
  • 物理AI与人形机器人:从实验室到产业化的关键跨越
  • 多线程和多进程编程中常见的性能瓶颈问题
  • C# 异步编程(使用异步Lambda表达式)
  • 专题二_滑动窗口_找到字符串中所有字母异位词
  • Arduino系列教程:点亮一个LED灯
  • 本地部署网络流量分析工具 ntopng 并实现外部访问( Windows 版本
  • C++高频知识点(十七)
  • 【lucene】HitsThresholdChecker命中阈值检测器
  • istio笔记03--快速上手多集群mesh
  • 本地WSL ubuntu部署whisper api服务
  • NVIDIA Jetson JetPack 全面解析:从硬件到定制镜像
  • 智能情趣设备、爆 bug:可被远程操控。。。
  • 目标检测数据集 - 无人机检测数据集下载「包含COCO、YOLO两种格式」
  • Python 中的 Mixin
  • 二十、MySQL-DQL-条件查询
  • 第八章:终极合体 —— 实现智能一键分组
  • 【Python 工具人快餐 · 第 1 份】
  • 【代码随想录|232.用栈实现队列、225.用队列实现栈、20.有效的括号、1047.删除字符串中的所有相邻重复项】
  • 第05章 排序与分页
  • 模板方法模式:优雅封装算法骨架
  • Python-UV-portry项目管理流程
  • redis8.0.3部署于mac
  • C++ 中的智能指针
  • Python 继承和多态
  • ElaWidgetTools qt5+vs2019编译
  • 1.JavaScript 介绍
  • 基于STM32的智能电表设计与实现
  • 计算机组成原理2-4-1:浮点数的表示