08-红黑树
💡 核心结论
红黑树本质
定义:自平衡二叉搜索树,通过颜色约束保持近似平衡
性能:所有操作O(log n),最坏情况有保证
平衡性:最长路径 ≤ 2倍最短路径(比AVL宽松)
核心:用颜色规则代替严格高度平衡,减少旋转次数
应用:C++ STL、Java TreeMap、Linux内核
红黑树 vs AVL树
特性 |
红黑树 |
AVL树 |
|---|---|---|
平衡度 |
近似平衡 |
严格平衡 |
插入旋转 |
≤2次 |
≤2次 |
删除旋转 |
≤3次 |
O(log n) |
查询性能 |
稍慢 |
最快 |
插入删除 |
最快 |
较慢 |
选择 |
插入删除多 |
查询多 |
五大性质(必背)
节点是红色或黑色
根节点是黑色
叶子节点(NIL)是黑色
红色节点的子节点都是黑色(无连续红色)
任一节点到叶子的所有路径包含相同数量的黑色节点
为什么这样设计
性质4:避免连续红色,限制红色节点数量
性质5:保证黑高度相同,确保平衡性
结果:最长路径(红黑交替)≤ 2倍最短路径(全黑)
🌳 红黑树性质
五大性质
节点是红色或黑色
根节点是黑色
所有叶子节点(NIL)是黑色
红色节点的两个子节点都是黑色(不能有连续的红色节点)
从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
性质保证
最长路径(红黑交替)≤ 最短路径(全黑)的2倍
树的高度:h ≤ 2log(n+1)
查找、插入、删除:O(log n)
🎯 红黑树 vs AVL树
特性 |
AVL树 |
红黑树 |
|---|---|---|
平衡性 |
严格平衡 |
近似平衡 |
平衡因子 |
高度差≤1 |
最长路径≤2倍最短路径 |
旋转次数 |
插入1-2次,删除O(log n) |
插入≤2次,删除≤3次 |
查询性能 |
更快 |
稍慢 |
插入删除 |
较慢 |
更快 |
应用场景 |
查询密集 |
插入删除密集 |
实际应用 |
Windows NT内核 |
Linux内核、C++ STL |
🔄 旋转操作
左旋
x y
/ \ / \
a y => x c
/ \ / \
b c a b
右旋
y x
/ \ / \
x c => a y
/ \ / \
a b b c
🎨 插入操作
插入步骤
按BST规则插入新节点(红色)
修复红黑树性质
情况分类处理
插入修复情况
情况1:叔叔是红色
父亲和叔叔变黑
爷爷变红
爷爷作为新节点继续修复
情况2:叔叔是黑色,当前节点是右孩子
左旋父节点
转换为情况3
情况3:叔叔是黑色,当前节点是左孩子
父亲变黑
爷爷变红
右旋爷爷
🗑️ 删除操作
删除步骤
按BST规则删除节点
如果删除的是黑色节点,需要修复
情况分类处理
删除修复情况
情况1:兄弟是红色
父亲变红
兄弟变黑
左旋父亲
转换为其他情况
情况2:兄弟是黑色,兄弟的两个孩子都是黑色
兄弟变红
父亲作为新节点继续修复
情况3:兄弟是黑色,兄弟的左孩子是红色,右孩子是黑色
兄弟变红
兄弟的左孩子变黑
右旋兄弟
转换为情况4
情况4:兄弟是黑色,兄弟的右孩子是红色
兄弟颜色 = 父亲颜色
父亲变黑
兄弟的右孩子变黑
左旋父亲
🔧 应用场景
C++ STL
std::mapstd::setstd::multimapstd::multiset
Java
TreeMapTreeSet
Linux内核
完全公平调度器(CFS)
虚拟内存管理
其他
epoll实现
nginx定时器
💡 实现要点
哨兵节点(NIL)
class NIL:
"""哨兵节点"""
def __init__(self):
self.color = BLACK
self.left = self
self.right = self
self.parent = None
# 使用全局NIL节点
NIL_NODE = NIL()
颜色表示
RED = 0
BLACK = 1
class RBNode:
def __init__(self, val, color=RED):
self.val = val
self.color = color
self.left = NIL_NODE
self.right = NIL_NODE
self.parent = None
📚 时间复杂度分析
操作 |
平均 |
最坏 |
|---|---|---|
查找 |
O(log n) |
O(log n) |
插入 |
O(log n) |
O(log n) |
删除 |
O(log n) |
O(log n) |
最小/最大 |
O(log n) |
O(log n) |
空间复杂度:O(n)
🎯 性能特点
优势
最坏情况性能保证 O(log n)
插入删除平均旋转次数少
实现相对简单(相比B树)
劣势
代码复杂度高于AVL树
常数因子较大
查询性能略逊于AVL树
📚 LeetCode练习
虽然LeetCode很少直接考察红黑树实现,但理解红黑树有助于:
理解STL容器性能
系统设计问题
面试中的数据结构选择
💡 学习建议
先掌握BST和AVL树
理解五大性质的作用
画图理解旋转和变色
重点掌握插入过程
删除操作可以适当简化理解
了解实际应用场景
📚 参考资料
《算法导论》第13章
《STL源码剖析》
Linux内核源码(rbtree.c)
💻 完整代码实现
Python 实现
1"""
2红黑树实现
3"""
4
5# 颜色常量
6RED = 0
7BLACK = 1
8
9
10class RBNode:
11 """红黑树节点"""
12
13 def __init__(self, val, color=RED):
14 self.val = val
15 self.color = color
16 self.left = None
17 self.right = None
18 self.parent = None
19
20
21class RBTree:
22 """红黑树实现"""
23
24 def __init__(self):
25 # 哨兵节点
26 self.NIL = RBNode(0, BLACK)
27 self.NIL.left = self.NIL
28 self.NIL.right = self.NIL
29
30 self.root = self.NIL
31
32 def insert(self, val):
33 """插入节点"""
34 # BST插入
35 new_node = RBNode(val, RED)
36 new_node.left = self.NIL
37 new_node.right = self.NIL
38
39 parent = None
40 curr = self.root
41
42 while curr != self.NIL:
43 parent = curr
44 if val < curr.val:
45 curr = curr.left
46 else:
47 curr = curr.right
48
49 new_node.parent = parent
50
51 if parent is None:
52 self.root = new_node
53 elif val < parent.val:
54 parent.left = new_node
55 else:
56 parent.right = new_node
57
58 # 修复红黑树性质
59 self._insert_fixup(new_node)
60
61 def _insert_fixup(self, node):
62 """插入后修复"""
63 while node.parent and node.parent.color == RED:
64 if node.parent == node.parent.parent.left:
65 uncle = node.parent.parent.right
66
67 if uncle.color == RED:
68 # 情况1:叔叔是红色
69 node.parent.color = BLACK
70 uncle.color = BLACK
71 node.parent.parent.color = RED
72 node = node.parent.parent
73 else:
74 if node == node.parent.right:
75 # 情况2:当前节点是右孩子
76 node = node.parent
77 self._left_rotate(node)
78
79 # 情况3:当前节点是左孩子
80 node.parent.color = BLACK
81 node.parent.parent.color = RED
82 self._right_rotate(node.parent.parent)
83 else:
84 # 对称情况
85 uncle = node.parent.parent.left
86
87 if uncle.color == RED:
88 node.parent.color = BLACK
89 uncle.color = BLACK
90 node.parent.parent.color = RED
91 node = node.parent.parent
92 else:
93 if node == node.parent.left:
94 node = node.parent
95 self._right_rotate(node)
96
97 node.parent.color = BLACK
98 node.parent.parent.color = RED
99 self._left_rotate(node.parent.parent)
100
101 self.root.color = BLACK
102
103 def _left_rotate(self, x):
104 """左旋"""
105 y = x.right
106 x.right = y.left
107
108 if y.left != self.NIL:
109 y.left.parent = x
110
111 y.parent = x.parent
112
113 if x.parent is None:
114 self.root = y
115 elif x == x.parent.left:
116 x.parent.left = y
117 else:
118 x.parent.right = y
119
120 y.left = x
121 x.parent = y
122
123 def _right_rotate(self, y):
124 """右旋"""
125 x = y.left
126 y.left = x.right
127
128 if x.right != self.NIL:
129 x.right.parent = y
130
131 x.parent = y.parent
132
133 if y.parent is None:
134 self.root = x
135 elif y == y.parent.left:
136 y.parent.left = x
137 else:
138 y.parent.right = x
139
140 x.right = y
141 y.parent = x
142
143 def search(self, val):
144 """查找节点"""
145 curr = self.root
146 while curr != self.NIL and curr.val != val:
147 if val < curr.val:
148 curr = curr.left
149 else:
150 curr = curr.right
151 return curr if curr != self.NIL else None
152
153 def inorder(self):
154 """中序遍历"""
155 result = []
156 self._inorder_helper(self.root, result)
157 return result
158
159 def _inorder_helper(self, node, result):
160 """中序遍历辅助函数"""
161 if node != self.NIL:
162 self._inorder_helper(node.left, result)
163 result.append(node.val)
164 self._inorder_helper(node.right, result)
165
166 def print_tree(self, node=None, level=0, prefix="Root: "):
167 """打印树结构"""
168 if node is None:
169 node = self.root
170
171 if node != self.NIL:
172 color = "🔴" if node.color == RED else "⚫"
173 print(" " * (level * 4) + prefix + f"{color}{node.val}")
174 if node.left != self.NIL or node.right != self.NIL:
175 self.print_tree(node.left, level + 1, "L--- ")
176 self.print_tree(node.right, level + 1, "R--- ")
177
178
179def demo():
180 """演示红黑树的使用"""
181 print("=== 红黑树演示 ===\n")
182
183 tree = RBTree()
184
185 # 插入节点
186 values = [7, 3, 18, 10, 22, 8, 11, 26, 2, 6, 13]
187 print(f"插入节点: {values}\n")
188
189 for val in values:
190 tree.insert(val)
191 print(f"插入 {val}:")
192 tree.print_tree()
193 print()
194
195 # 中序遍历
196 print("中序遍历(应该是有序的):")
197 print(tree.inorder())
198 print()
199
200 # 查找
201 search_val = 10
202 result = tree.search(search_val)
203 if result:
204 color = "红色" if result.color == RED else "黑色"
205 print(f"找到节点 {search_val},颜色: {color}")
206 else:
207 print(f"未找到节点 {search_val}")
208
209
210if __name__ == '__main__':
211 demo()
212
C++ 实现
1/**
2 * 红黑树实现(简化版,仅实现插入)
3 * 完整实现较复杂,建议学习STL源码
4 */
5
6#include <iostream>
7
8enum Color { RED, BLACK };
9
10struct RBNode {
11 int val;
12 Color color;
13 RBNode* left;
14 RBNode* right;
15 RBNode* parent;
16
17 RBNode(int v) : val(v), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
18};
19
20
21class RBTree {
22private:
23 RBNode* root;
24 RBNode* NIL; // 哨兵节点
25
26 void leftRotate(RBNode* x) {
27 RBNode* y = x->right;
28 x->right = y->left;
29
30 if (y->left != NIL) {
31 y->left->parent = x;
32 }
33
34 y->parent = x->parent;
35
36 if (!x->parent) {
37 root = y;
38 } else if (x == x->parent->left) {
39 x->parent->left = y;
40 } else {
41 x->parent->right = y;
42 }
43
44 y->left = x;
45 x->parent = y;
46 }
47
48 void rightRotate(RBNode* y) {
49 RBNode* x = y->left;
50 y->left = x->right;
51
52 if (x->right != NIL) {
53 x->right->parent = y;
54 }
55
56 x->parent = y->parent;
57
58 if (!y->parent) {
59 root = x;
60 } else if (y == y->parent->left) {
61 y->parent->left = x;
62 } else {
63 y->parent->right = x;
64 }
65
66 x->right = y;
67 y->parent = x;
68 }
69
70 void insertFixup(RBNode* node) {
71 while (node->parent && node->parent->color == RED) {
72 if (node->parent == node->parent->parent->left) {
73 RBNode* uncle = node->parent->parent->right;
74
75 if (uncle->color == RED) {
76 // 情况1
77 node->parent->color = BLACK;
78 uncle->color = BLACK;
79 node->parent->parent->color = RED;
80 node = node->parent->parent;
81 } else {
82 if (node == node->parent->right) {
83 // 情况2
84 node = node->parent;
85 leftRotate(node);
86 }
87 // 情况3
88 node->parent->color = BLACK;
89 node->parent->parent->color = RED;
90 rightRotate(node->parent->parent);
91 }
92 } else {
93 RBNode* uncle = node->parent->parent->left;
94
95 if (uncle->color == RED) {
96 node->parent->color = BLACK;
97 uncle->color = BLACK;
98 node->parent->parent->color = RED;
99 node = node->parent->parent;
100 } else {
101 if (node == node->parent->left) {
102 node = node->parent;
103 rightRotate(node);
104 }
105 node->parent->color = BLACK;
106 node->parent->parent->color = RED;
107 leftRotate(node->parent->parent);
108 }
109 }
110 }
111 root->color = BLACK;
112 }
113
114 void printTreeHelper(RBNode* node, int level, std::string prefix) {
115 if (node && node != NIL) {
116 std::string colorStr = (node->color == RED) ? "🔴" : "⚫";
117 std::cout << std::string(level * 4, ' ') << prefix
118 << colorStr << node->val << std::endl;
119 if (node->left != NIL || node->right != NIL) {
120 printTreeHelper(node->left, level + 1, "L--- ");
121 printTreeHelper(node->right, level + 1, "R--- ");
122 }
123 }
124 }
125
126public:
127 RBTree() {
128 NIL = new RBNode(0);
129 NIL->color = BLACK;
130 NIL->left = NIL->right = NIL->parent = nullptr;
131 root = NIL;
132 }
133
134 void insert(int val) {
135 RBNode* newNode = new RBNode(val);
136 newNode->left = NIL;
137 newNode->right = NIL;
138
139 RBNode* parent = nullptr;
140 RBNode* curr = root;
141
142 while (curr != NIL) {
143 parent = curr;
144 if (val < curr->val) {
145 curr = curr->left;
146 } else {
147 curr = curr->right;
148 }
149 }
150
151 newNode->parent = parent;
152
153 if (!parent) {
154 root = newNode;
155 } else if (val < parent->val) {
156 parent->left = newNode;
157 } else {
158 parent->right = newNode;
159 }
160
161 insertFixup(newNode);
162 }
163
164 void printTree() {
165 printTreeHelper(root, 0, "Root: ");
166 }
167};
168
169
170int main() {
171 std::cout << "=== 红黑树演示 ===" << std::endl << std::endl;
172
173 RBTree tree;
174
175 std::vector<int> values = {7, 3, 18, 10, 22, 8, 11, 26};
176 std::cout << "插入节点: ";
177 for (int val : values) {
178 std::cout << val << " ";
179 }
180 std::cout << std::endl << std::endl;
181
182 for (int val : values) {
183 tree.insert(val);
184 std::cout << "插入 " << val << ":" << std::endl;
185 tree.printTree();
186 std::cout << std::endl;
187 }
188
189 return 0;
190}