3-4 红黑树
红黑树(Red-Black Tree)
红黑树(Red-Black Tree)是一种自平衡二叉搜索树(Self-Balancing Binary Search Tree)。每个节点额外存储一个颜色属性(红色或黑色),通过颜色约束来保证树的高度近似平衡,从而确保查找、插入、删除等操作的时间复杂度均为 O(log n)。
红黑树在实际工程中应用广泛:
- C++ 标准库中的
std::map和std::set - Java 中的
TreeMap和TreeSet - Linux 内核的进程调度器(CFS, Completely Fair Scheduler)
- ext3/ext4 文件系统中的目录索引
与 AVL 树(AVL Tree)相比,红黑树的平衡条件更加宽松,插入和删除时需要的旋转操作更少,因此在写入频繁的场景下性能更优。
红黑树的性质
红黑树必须满足以下五条性质:
- 每个节点不是红色就是黑色 — 节点的颜色只能是这两种之一。
- 根节点是黑色 — 树的根节点必须为黑色。
- 每个叶子节点(NIL 节点)是黑色 — 这里的叶子指的是空节点(NIL),而不是含有数据的节点。
- 红色节点的两个子节点必须是黑色 — 不能有两个连续的红色节点(即从根到叶子的路径上不会出现两个相邻的红色节点)。
- 从任意节点到其每个叶子节点的所有路径都包含相同数目的黑色节点 — 这条性质保证了树的高度平衡。
其中性质 4 和性质 5 是红黑树保持平衡的核心约束。性质 5 保证了最长路径不超过最短路径的两倍,因为最长路径只能是红黑交替,而最短路径全是黑节点,且两者黑节点数量相同。
B(20)
/ \
R(10) R(30)
/ \ / \
NIL NIL NIL NIL
从根节点 20 到任意 NIL 的路径上,
黑色节点数(含 NIL)= 2(节点20 + NIL)
满足所有红黑树性质。
节点定义
红黑树节点在普通二叉搜索树节点的基础上增加了颜色(Color)属性和父节点(parent)指针。颜色通常用枚举表示:RED(红色)或 BLACK(黑色)。
C++ 节点定义
enum Color { RED, BLACK };
struct Node {
int data;
Color color;
Node* left;
Node* right;
Node* parent;
// constructor: new nodes default to RED
Node(int val) : data(val), color(RED),
left(nullptr), right(nullptr), parent(nullptr) {}
};
新插入的节点默认设为红色,因为插入红色节点不会违反性质 5(黑高不变),只可能违反性质 4(不能有连续红色节点),而修复性质 4 的代价较小。
C 节点定义
typedef enum { RED, BLACK } Color;
typedef struct Node {
int data;
Color color;
struct Node* left;
struct Node* right;
struct Node* parent;
} Node;
// create a new node with given value, default color is RED
Node* createNode(int val) {
Node* node = (Node*)malloc(sizeof(Node));
node->data = val;
node->color = RED;
node->left = NULL;
node->right = NULL;
node->parent = NULL;
return node;
}
C 语言使用 typedef 定义结构体和枚举,并通过 malloc 动态分配内存。
Python 节点定义
class Node:
def __init__(self, data, color='RED'):
self.data = data
self.color = color # 'RED' or 'BLACK'
self.left = None
self.right = None
self.parent = None
Python 使用字符串 'RED' 和 'BLACK' 表示颜色,代码更加简洁直观。
Go 节点定义
package main
const (
RED = 0
BLACK = 1
)
type Node struct {
data int
color int // RED or BLACK
left *Node
right *Node
parent *Node
}
// create a new node with given value, default color is RED
func newNode(val int) *Node {
return &Node{
data: val,
color: RED,
left: nil,
right: nil,
parent: nil,
}
}
Go 使用常量 RED = 0 和 BLACK = 1 表示颜色,通过结构体指针实现节点间的引用关系。
旋转操作
旋转(Rotation)是红黑树维护平衡的基本操作。旋转分为左旋(Left Rotation)和右旋(Right Rotation),它们改变节点之间的父子关系,但保持二叉搜索树的性质。
左旋示意:以节点 x 为轴,将其右子节点 y 提升为新的父节点,x 变为 y 的左子节点。
左旋前 左旋后
x y
/ \ / \
a y => x c
/ \ / \
b c a b
右旋示意:以节点 y 为轴,将其左子节点 x 提升为新的父节点,y 变为 x 的右子节点。
右旋前 右旋后
y x
/ \ / \
x c => a y
/ \ / \
a b b c
C++ 旋转实现
class RedBlackTree {
private:
Node* root;
// left rotate around node x
void leftRotate(Node* x) {
Node* y = x->right; // set y
x->right = y->left; // turn y's left subtree into x's right subtree
if (y->left != nullptr)
y->left->parent = x;
y->parent = x->parent; // link x's parent to y
if (x->parent == nullptr)
root = y;
else if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->left = x; // put x on y's left
x->parent = y;
}
// right rotate around node y
void rightRotate(Node* y) {
Node* x = y->left; // set x
y->left = x->right; // turn x's right subtree into y's left subtree
if (x->right != nullptr)
x->right->parent = y;
x->parent = y->parent; // link y's parent to x
if (y->parent == nullptr)
root = x;
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
x->right = y; // put y on x's right
y->parent = x;
}
public:
RedBlackTree() : root(nullptr) {}
};
左旋将右子节点提升为父节点,右旋将左子节点提升为父节点。旋转操作只改变节点之间的连接关系,不改变中序遍历的顺序。
C 旋转实现
typedef struct {
Node* root;
} RedBlackTree;
// left rotate around node x
void leftRotate(RedBlackTree* tree, Node* x) {
Node* y = x->right;
x->right = y->left;
if (y->left != NULL)
y->left->parent = x;
y->parent = x->parent;
if (x->parent == NULL)
tree->root = y;
else if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->left = x;
x->parent = y;
}
// right rotate around node y
void rightRotate(RedBlackTree* tree, Node* y) {
Node* x = y->left;
y->left = x->right;
if (x->right != NULL)
x->right->parent = y;
x->parent = y->parent;
if (y->parent == NULL)
tree->root = x;
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
x->right = y;
y->parent = x;
}
C 版本通过传递 RedBlackTree 结构体指针来操作树的根节点,逻辑与 C++ 版本完全一致。
Python 旋转实现
class RedBlackTree:
def __init__(self):
self.root = None
def left_rotate(self, x):
y = x.right
x.right = y.left
if y.left is not None:
y.left.parent = x
y.parent = x.parent
if x.parent is None:
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
y.left = x.right
if x.right is not None:
x.right.parent = y
x.parent = y.parent
if y.parent is None:
self.root = x
elif y == y.parent.left:
y.parent.left = x
else:
y.parent.right = x
x.right = y
y.parent = x
Python 版本使用 None 替代 nullptr/NULL,其余逻辑与 C++/C 完全相同。
Go 旋转实现
type RedBlackTree struct {
root *Node
}
// left rotate around node x
func (t *RedBlackTree) leftRotate(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 {
t.root = y
} else if x == x.parent.left {
x.parent.left = y
} else {
x.parent.right = y
}
y.left = x
x.parent = y
}
// right rotate around node y
func (t *RedBlackTree) rightRotate(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 {
t.root = x
} else if y == y.parent.left {
y.parent.left = x
} else {
y.parent.right = x
}
x.right = y
y.parent = x
}
Go 使用方法的接收者(receiver)来操作树结构,nil 替代 nullptr/NULL,逻辑与其他语言版本完全一致。
插入操作
红黑树的插入分为两步:
- 标准 BST 插入 — 按照二叉搜索树的方式找到插入位置,新节点颜色设为红色。
- 修复违规(Fixup) — 检查是否违反红黑树性质,通过重新着色(Recoloring)和旋转(Rotation)修复。
新节点设为红色的原因:插入红色节点不会影响黑高(性质 5),只可能违反性质 4(红色节点的子节点必须是黑色)。只需修复这一种违规即可。
修复过程中,定义"叔节点(Uncle)"为当前节点父节点的兄弟节点。根据叔节点的颜色和当前节点的位置,分为三种情况:
- 情况 1:叔节点是红色 — 将父节点和叔节点变为黑色,祖父节点变为红色,然后将祖父节点作为新的当前节点继续向上检查。
- 情况 2:叔节点是黑色,且当前节点是父节点的右子节点 — 对父节点执行左旋,转化为情况 3。
- 情况 3:叔节点是黑色,且当前节点是父节点的左子节点 — 将父节点变为黑色,祖父节点变为红色,对祖父节点执行右旋。
C++ 插入实现
class RedBlackTree {
private:
Node* root;
void leftRotate(Node* x) {
Node* y = x->right;
x->right = y->left;
if (y->left != nullptr)
y->left->parent = x;
y->parent = x->parent;
if (x->parent == nullptr)
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 != nullptr)
x->right->parent = y;
x->parent = y->parent;
if (y->parent == nullptr)
root = x;
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
x->right = y;
y->parent = x;
}
// fix red-black tree violations after insertion
void insertFixup(Node* z) {
while (z->parent != nullptr && z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
Node* uncle = z->parent->parent->right;
// Case 1: uncle is red -> recolor
if (uncle != nullptr && uncle->color == RED) {
z->parent->color = BLACK;
uncle->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
// Case 2: uncle is black, z is right child -> left rotate
if (z == z->parent->right) {
z = z->parent;
leftRotate(z);
}
// Case 3: uncle is black, z is left child -> right rotate
z->parent->color = BLACK;
z->parent->parent->color = RED;
rightRotate(z->parent->parent);
}
} else {
// mirror case: parent is right child of grandparent
Node* uncle = z->parent->parent->left;
if (uncle != nullptr && uncle->color == RED) {
z->parent->color = BLACK;
uncle->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; // ensure root is always black
}
public:
RedBlackTree() : root(nullptr) {}
void insert(int val) {
Node* z = new Node(val);
Node* y = nullptr;
Node* x = root;
// standard BST insert: find position
while (x != nullptr) {
y = x;
if (z->data < x->data)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y == nullptr)
root = z;
else if (z->data < y->data)
y->left = z;
else
y->right = z;
// fix red-black tree violations
insertFixup(z);
}
};
插入操作首先按照标准 BST 方式找到插入位置,将新节点(红色)挂到树上,然后调用 insertFixup 修复可能违反的红黑树性质。修复函数通过 while 循环向上逐层检查,直到根节点或父节点为黑色为止。
C 插入实现
void insertFixup(RedBlackTree* tree, Node* z) {
while (z->parent != NULL && z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
Node* uncle = z->parent->parent->right;
if (uncle != NULL && uncle->color == RED) {
// Case 1: uncle is red -> recolor
z->parent->color = BLACK;
uncle->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->right) {
// Case 2: left rotate
z = z->parent;
leftRotate(tree, z);
}
// Case 3: right rotate
z->parent->color = BLACK;
z->parent->parent->color = RED;
rightRotate(tree, z->parent->parent);
}
} else {
Node* uncle = z->parent->parent->left;
if (uncle != NULL && uncle->color == RED) {
z->parent->color = BLACK;
uncle->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->left) {
z = z->parent;
rightRotate(tree, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
leftRotate(tree, z->parent->parent);
}
}
}
tree->root->color = BLACK;
}
void insert(RedBlackTree* tree, int val) {
Node* z = createNode(val);
Node* y = NULL;
Node* x = tree->root;
while (x != NULL) {
y = x;
if (z->data < x->data)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y == NULL)
tree->root = z;
else if (z->data < y->data)
y->left = z;
else
y->right = z;
insertFixup(tree, z);
}
C 版本的插入逻辑与 C++ 完全一致,只是需要显式传递 RedBlackTree* 指针。
Python 插入实现
def insert(self, val):
z = Node(val)
y = None
x = self.root
while x is not None:
y = x
if z.data < x.data:
x = x.left
else:
x = x.right
z.parent = y
if y is None:
self.root = z
elif z.data < y.data:
y.left = z
else:
y.right = z
self._insert_fixup(z)
def _insert_fixup(self, z):
while z.parent is not None and z.parent.color == 'RED':
if z.parent == z.parent.parent.left:
uncle = z.parent.parent.right
if uncle is not None and uncle.color == 'RED':
# Case 1: uncle is red -> recolor
z.parent.color = 'BLACK'
uncle.color = 'BLACK'
z.parent.parent.color = 'RED'
z = z.parent.parent
else:
if z == z.parent.right:
# Case 2: left rotate
z = z.parent
self.left_rotate(z)
# Case 3: right rotate
z.parent.color = 'BLACK'
z.parent.parent.color = 'RED'
self.right_rotate(z.parent.parent)
else:
uncle = z.parent.parent.left
if uncle is not None and uncle.color == 'RED':
z.parent.color = 'BLACK'
uncle.color = 'BLACK'
z.parent.parent.color = 'RED'
z = z.parent.parent
else:
if z == z.parent.left:
z = z.parent
self.right_rotate(z)
z.parent.color = 'BLACK'
z.parent.parent.color = 'RED'
self.left_rotate(z.parent.parent)
self.root.color = 'BLACK'
Python 版本使用字符串 'RED' 和 'BLACK',逻辑结构与其他语言版本完全对应。
Go 插入实现
// fix red-black tree violations after insertion
func (t *RedBlackTree) insertFixup(z *Node) {
for z.parent != nil && z.parent.color == RED {
if z.parent == z.parent.parent.left {
uncle := z.parent.parent.right
if uncle != nil && uncle.color == RED {
// Case 1: uncle is red -> recolor
z.parent.color = BLACK
uncle.color = BLACK
z.parent.parent.color = RED
z = z.parent.parent
} else {
if z == z.parent.right {
// Case 2: left rotate
z = z.parent
t.leftRotate(z)
}
// Case 3: right rotate
z.parent.color = BLACK
z.parent.parent.color = RED
t.rightRotate(z.parent.parent)
}
} else {
// mirror case: parent is right child of grandparent
uncle := z.parent.parent.left
if uncle != nil && uncle.color == RED {
z.parent.color = BLACK
uncle.color = BLACK
z.parent.parent.color = RED
z = z.parent.parent
} else {
if z == z.parent.left {
z = z.parent
t.rightRotate(z)
}
z.parent.color = BLACK
z.parent.parent.color = RED
t.leftRotate(z.parent.parent)
}
}
}
t.root.color = BLACK // ensure root is always black
}
func (t *RedBlackTree) insert(val int) {
z := newNode(val)
var y *Node
x := t.root
// standard BST insert: find position
for x != nil {
y = x
if z.data < x.data {
x = x.left
} else {
x = x.right
}
}
z.parent = y
if y == nil {
t.root = z
} else if z.data < y.data {
y.left = z
} else {
y.right = z
}
// fix red-black tree violations
t.insertFixup(z)
}
Go 版本使用 for 循环替代 while,通过方法接收者操作树结构,插入和修复逻辑与其他语言版本完全对应。
搜索操作
红黑树的搜索(Search)操作与普通二叉搜索树完全相同:从根节点开始,如果目标值小于当前节点则进入左子树,大于则进入右子树,相等则找到目标。
C++ 搜索实现
Node* search(int val) {
Node* curr = root;
while (curr != nullptr) {
if (val < curr->data)
curr = curr->left;
else if (val > curr->data)
curr = curr->right;
else
return curr; // found
}
return nullptr; // not found
}
C 搜索实现
Node* search(RedBlackTree* tree, int val) {
Node* curr = tree->root;
while (curr != NULL) {
if (val < curr->data)
curr = curr->left;
else if (val > curr->data)
curr = curr->right;
else
return curr;
}
return NULL;
}
Python 搜索实现
def search(self, val):
curr = self.root
while curr is not None:
if val < curr.data:
curr = curr.left
elif val > curr.data:
curr = curr.right
else:
return curr
return None
Go 搜索实现
func (t *RedBlackTree) search(val int) *Node {
curr := t.root
for curr != nil {
if val < curr.data {
curr = curr.left
} else if val > curr.data {
curr = curr.right
} else {
return curr // found
}
}
return nil // not found
}
搜索操作不涉及颜色属性,时间复杂度为 O(log n),与普通平衡 BST 相同。
遍历操作
中序遍历(Inorder Traversal)按照左子树 -> 根节点 -> 右子树的顺序访问节点。对于二叉搜索树,中序遍历的结果是有序的。在红黑树中,我们在输出节点值的同时输出颜色信息,格式为 值(颜色),例如 10(B) 表示值为 10 的黑色节点。
C++ 遍历实现
void inorderHelper(Node* node) {
if (node == nullptr) return;
inorderHelper(node->left);
// print node with color: R for RED, B for BLACK
std::cout << node->data << "("
<< (node->color == RED ? "R" : "B") << ") ";
inorderHelper(node->right);
}
void inorder() {
inorderHelper(root);
std::cout << std::endl;
}
C 遍历实现
void inorderHelper(Node* node) {
if (node == NULL) return;
inorderHelper(node->left);
printf("%d(%s) ", node->data,
node->color == RED ? "R" : "B");
inorderHelper(node->right);
}
void inorder(RedBlackTree* tree) {
inorderHelper(tree->root);
printf("\n");
}
Python 遍历实现
def inorder_helper(self, node):
if node is None:
return
self.inorder_helper(node.left)
color = 'R' if node.color == 'RED' else 'B'
print(f"{node.data}({color})", end=' ')
self.inorder_helper(node.right)
def inorder(self):
self.inorder_helper(self.root)
print()
Go 遍历实现
func inorderHelper(node *Node) {
if node == nil {
return
}
inorderHelper(node.left)
color := "B"
if node.color == RED {
color = "R"
}
fmt.Printf("%d(%s) ", node.data, color)
inorderHelper(node.right)
}
func (t *RedBlackTree) inorder() {
inorderHelper(t.root)
fmt.Println()
}
Go 版本使用 fmt.Printf 输出节点值和颜色信息,格式与 C/Python 版本保持一致。
完整实现
以下是将上述所有部分组合在一起的完整红黑树程序。插入序列为 10, 20, 30, 15, 25, 5, 8,然后进行中序遍历(显示颜色)和搜索操作。
C++ 完整实现
#include <iostream>
using namespace std;
enum Color { RED, BLACK };
struct Node {
int data;
Color color;
Node* left;
Node* right;
Node* parent;
Node(int val) : data(val), color(RED),
left(nullptr), right(nullptr), parent(nullptr) {}
};
class RedBlackTree {
private:
Node* root;
void leftRotate(Node* x) {
Node* y = x->right;
x->right = y->left;
if (y->left != nullptr)
y->left->parent = x;
y->parent = x->parent;
if (x->parent == nullptr)
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 != nullptr)
x->right->parent = y;
x->parent = y->parent;
if (y->parent == nullptr)
root = x;
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
x->right = y;
y->parent = x;
}
void insertFixup(Node* z) {
while (z->parent != nullptr && z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
Node* uncle = z->parent->parent->right;
if (uncle != nullptr && uncle->color == RED) {
z->parent->color = BLACK;
uncle->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->right) {
z = z->parent;
leftRotate(z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rightRotate(z->parent->parent);
}
} else {
Node* uncle = z->parent->parent->left;
if (uncle != nullptr && uncle->color == RED) {
z->parent->color = BLACK;
uncle->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 inorderHelper(Node* node) {
if (node == nullptr) return;
inorderHelper(node->left);
cout << node->data << "("
<< (node->color == RED ? "R" : "B") << ") ";
inorderHelper(node->right);
}
Node* searchHelper(int val) {
Node* curr = root;
while (curr != nullptr) {
if (val < curr->data)
curr = curr->left;
else if (val > curr->data)
curr = curr->right;
else
return curr;
}
return nullptr;
}
public:
RedBlackTree() : root(nullptr) {}
void insert(int val) {
Node* z = new Node(val);
Node* y = nullptr;
Node* x = root;
while (x != nullptr) {
y = x;
if (z->data < x->data)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y == nullptr)
root = z;
else if (z->data < y->data)
y->left = z;
else
y->right = z;
insertFixup(z);
}
void inorder() {
inorderHelper(root);
cout << endl;
}
bool search(int val) {
return searchHelper(val) != nullptr;
}
};
int main() {
RedBlackTree tree;
// insert sequence
int values[] = {10, 20, 30, 15, 25, 5, 8};
for (int v : values) {
tree.insert(v);
}
cout << "Inorder traversal: ";
tree.inorder();
// search operations
cout << "Search 15: " << (tree.search(15) ? "Found" : "Not found") << endl;
cout << "Search 99: " << (tree.search(99) ? "Found" : "Not found") << endl;
return 0;
}
运行该程序将输出:
Inorder traversal: 5(B) 8(R) 10(B) 15(B) 20(B) 25(R) 30(B)
Search 15: Found
Search 99: Not found
中序遍历的结果是升序排列的,括号中的字母表示节点颜色(R = 红色, B = 黑色)。可以看到根节点 20 是黑色,没有相邻的红色节点,满足所有红黑树性质。
C 完整实现
#include <stdio.h>
#include <stdlib.h>
typedef enum { RED, BLACK } Color;
typedef struct Node {
int data;
Color color;
struct Node* left;
struct Node* right;
struct Node* parent;
} Node;
typedef struct {
Node* root;
} RedBlackTree;
Node* createNode(int val) {
Node* node = (Node*)malloc(sizeof(Node));
node->data = val;
node->color = RED;
node->left = NULL;
node->right = NULL;
node->parent = NULL;
return node;
}
void leftRotate(RedBlackTree* tree, Node* x) {
Node* y = x->right;
x->right = y->left;
if (y->left != NULL)
y->left->parent = x;
y->parent = x->parent;
if (x->parent == NULL)
tree->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(RedBlackTree* tree, Node* y) {
Node* x = y->left;
y->left = x->right;
if (x->right != NULL)
x->right->parent = y;
x->parent = y->parent;
if (y->parent == NULL)
tree->root = x;
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
x->right = y;
y->parent = x;
}
void insertFixup(RedBlackTree* tree, Node* z) {
while (z->parent != NULL && z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
Node* uncle = z->parent->parent->right;
if (uncle != NULL && uncle->color == RED) {
z->parent->color = BLACK;
uncle->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->right) {
z = z->parent;
leftRotate(tree, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rightRotate(tree, z->parent->parent);
}
} else {
Node* uncle = z->parent->parent->left;
if (uncle != NULL && uncle->color == RED) {
z->parent->color = BLACK;
uncle->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->left) {
z = z->parent;
rightRotate(tree, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
leftRotate(tree, z->parent->parent);
}
}
}
tree->root->color = BLACK;
}
void insert(RedBlackTree* tree, int val) {
Node* z = createNode(val);
Node* y = NULL;
Node* x = tree->root;
while (x != NULL) {
y = x;
if (z->data < x->data)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y == NULL)
tree->root = z;
else if (z->data < y->data)
y->left = z;
else
y->right = z;
insertFixup(tree, z);
}
void inorderHelper(Node* node) {
if (node == NULL) return;
inorderHelper(node->left);
printf("%d(%s) ", node->data,
node->color == RED ? "R" : "B");
inorderHelper(node->right);
}
void inorder(RedBlackTree* tree) {
inorderHelper(tree->root);
printf("\n");
}
Node* search(RedBlackTree* tree, int val) {
Node* curr = tree->root;
while (curr != NULL) {
if (val < curr->data)
curr = curr->left;
else if (val > curr->data)
curr = curr->right;
else
return curr;
}
return NULL;
}
int main() {
RedBlackTree tree;
tree.root = NULL;
int values[] = {10, 20, 30, 15, 25, 5, 8};
int n = sizeof(values) / sizeof(values[0]);
for (int i = 0; i < n; i++) {
insert(&tree, values[i]);
}
printf("Inorder traversal: ");
inorder(&tree);
printf("Search 15: %s\n", search(&tree, 15) ? "Found" : "Not found");
printf("Search 99: %s\n", search(&tree, 99) ? "Found" : "Not found");
return 0;
}
运行该程序将输出:
Inorder traversal: 5(B) 8(R) 10(B) 15(B) 20(B) 25(R) 30(B)
Search 15: Found
Search 99: Not found
C 版本的输出结果与 C++ 版本完全一致。
Python 完整实现
class Node:
def __init__(self, data, color='RED'):
self.data = data
self.color = color
self.left = None
self.right = None
self.parent = None
class RedBlackTree:
def __init__(self):
self.root = None
def left_rotate(self, x):
y = x.right
x.right = y.left
if y.left is not None:
y.left.parent = x
y.parent = x.parent
if x.parent is None:
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
y.left = x.right
if x.right is not None:
x.right.parent = y
x.parent = y.parent
if y.parent is None:
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(self, val):
z = Node(val)
y = None
x = self.root
while x is not None:
y = x
if z.data < x.data:
x = x.left
else:
x = x.right
z.parent = y
if y is None:
self.root = z
elif z.data < y.data:
y.left = z
else:
y.right = z
self._insert_fixup(z)
def _insert_fixup(self, z):
while z.parent is not None and z.parent.color == 'RED':
if z.parent == z.parent.parent.left:
uncle = z.parent.parent.right
if uncle is not None and uncle.color == 'RED':
z.parent.color = 'BLACK'
uncle.color = 'BLACK'
z.parent.parent.color = 'RED'
z = z.parent.parent
else:
if z == z.parent.right:
z = z.parent
self.left_rotate(z)
z.parent.color = 'BLACK'
z.parent.parent.color = 'RED'
self.right_rotate(z.parent.parent)
else:
uncle = z.parent.parent.left
if uncle is not None and uncle.color == 'RED':
z.parent.color = 'BLACK'
uncle.color = 'BLACK'
z.parent.parent.color = 'RED'
z = z.parent.parent
else:
if z == z.parent.left:
z = z.parent
self.right_rotate(z)
z.parent.color = 'BLACK'
z.parent.parent.color = 'RED'
self.left_rotate(z.parent.parent)
self.root.color = 'BLACK'
def inorder_helper(self, node):
if node is None:
return
self.inorder_helper(node.left)
color = 'R' if node.color == 'RED' else 'B'
print(f"{node.data}({color})", end=' ')
self.inorder_helper(node.right)
def inorder(self):
self.inorder_helper(self.root)
print()
def search(self, val):
curr = self.root
while curr is not None:
if val < curr.data:
curr = curr.left
elif val > curr.data:
curr = curr.right
else:
return True
return False
if __name__ == '__main__':
tree = RedBlackTree()
for v in [10, 20, 30, 15, 25, 5, 8]:
tree.insert(v)
print("Inorder traversal: ", end='')
tree.inorder()
print(f"Search 15: {'Found' if tree.search(15) else 'Not found'}")
print(f"Search 99: {'Found' if tree.search(99) else 'Not found'}")
运行该程序将输出:
Inorder traversal: 5(B) 8(R) 10(B) 15(B) 20(B) 25(R) 30(B)
Search 15: Found
Search 99: Not found
三个语言版本的输出结果完全一致。插入 10, 20, 30, 15, 25, 5, 8 后,最终的树结构为:
20(B)
/ \
10(B) 30(B)
/ \ /
5(B) 15(B) 25(R)
\
8(R)
可以验证:根节点 20 为黑色,每条从根到叶子(NIL)的路径上黑色节点数均为 3(含 NIL),没有相邻的红色节点,满足全部五条红黑树性质。
Go 完整实现
package main
import "fmt"
const (
RED = 0
BLACK = 1
)
type Node struct {
data int
color int
left *Node
right *Node
parent *Node
}
func newNode(val int) *Node {
return &Node{
data: val,
color: RED,
}
}
type RedBlackTree struct {
root *Node
}
func (t *RedBlackTree) leftRotate(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 {
t.root = y
} else if x == x.parent.left {
x.parent.left = y
} else {
x.parent.right = y
}
y.left = x
x.parent = y
}
func (t *RedBlackTree) rightRotate(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 {
t.root = x
} else if y == y.parent.left {
y.parent.left = x
} else {
y.parent.right = x
}
x.right = y
y.parent = x
}
func (t *RedBlackTree) insertFixup(z *Node) {
for z.parent != nil && z.parent.color == RED {
if z.parent == z.parent.parent.left {
uncle := z.parent.parent.right
if uncle != nil && uncle.color == RED {
z.parent.color = BLACK
uncle.color = BLACK
z.parent.parent.color = RED
z = z.parent.parent
} else {
if z == z.parent.right {
z = z.parent
t.leftRotate(z)
}
z.parent.color = BLACK
z.parent.parent.color = RED
t.rightRotate(z.parent.parent)
}
} else {
uncle := z.parent.parent.left
if uncle != nil && uncle.color == RED {
z.parent.color = BLACK
uncle.color = BLACK
z.parent.parent.color = RED
z = z.parent.parent
} else {
if z == z.parent.left {
z = z.parent
t.rightRotate(z)
}
z.parent.color = BLACK
z.parent.parent.color = RED
t.leftRotate(z.parent.parent)
}
}
}
t.root.color = BLACK
}
func (t *RedBlackTree) insert(val int) {
z := newNode(val)
var y *Node
x := t.root
for x != nil {
y = x
if z.data < x.data {
x = x.left
} else {
x = x.right
}
}
z.parent = y
if y == nil {
t.root = z
} else if z.data < y.data {
y.left = z
} else {
y.right = z
}
t.insertFixup(z)
}
func inorderHelper(node *Node) {
if node == nil {
return
}
inorderHelper(node.left)
color := "B"
if node.color == RED {
color = "R"
}
fmt.Printf("%d(%s) ", node.data, color)
inorderHelper(node.right)
}
func (t *RedBlackTree) inorder() {
inorderHelper(t.root)
fmt.Println()
}
func (t *RedBlackTree) search(val int) bool {
curr := t.root
for curr != nil {
if val < curr.data {
curr = curr.left
} else if val > curr.data {
curr = curr.right
} else {
return true
}
}
return false
}
func main() {
tree := &RedBlackTree{}
values := []int{10, 20, 30, 15, 25, 5, 8}
for _, v := range values {
tree.insert(v)
}
fmt.Print("Inorder traversal: ")
tree.inorder()
fmt.Printf("Search 15: %s\n", func() string {
if tree.search(15) {
return "Found"
}
return "Not found"
}())
fmt.Printf("Search 99: %s\n", func() string {
if tree.search(99) {
return "Found"
}
return "Not found"
}())
}
运行该程序将输出:
Inorder traversal: 5(B) 8(R) 10(B) 15(B) 20(B) 25(R) 30(B)
Search 15: Found
Search 99: Not found
四个语言版本的输出结果完全一致。Go 使用结构体指针和方法接收者实现面向对象风格,无需额外的类定义。
红黑树与其他平衡树的对比
红黑树和 AVL 树是最常用的两种自平衡二叉搜索树,它们各有优势。
| 特性 | AVL 树(AVL Tree) | 红黑树(Red-Black Tree) |
|---|---|---|
| 平衡严格度 | 严格平衡,左右子树高度差不超过 1 | 近似平衡,最长路径不超过最短路径的 2 倍 |
| 查找性能 | 更优(树更矮) | 略逊于 AVL 树 |
| 插入旋转次数 | 最多 2 次旋转 | 最多 2 次旋转 |
| 删除旋转次数 | 最多 O(log n) 次旋转 | 最多 3 次旋转 |
| 适用场景 | 查找密集型应用 | 插入/删除密集型应用 |
| 实现复杂度 | 相对简单 | 相对复杂 |
选择建议:
- 如果操作以查找为主,选择 AVL 树,因为更严格的平衡保证了更小的树高。
- 如果操作以插入和删除为主,选择红黑树,因为删除操作的旋转次数更少,性能更稳定。
红黑树的实际应用:
| 应用 | 说明 |
|---|---|
C++ std::map / std::set |
STL 关联容器的底层实现 |
Java TreeMap / TreeSet |
Java 集合框架中的有序映射和集合 |
| Linux CFS 调度器 | 完全公平调度器用红黑树管理进程虚拟运行时间 |
| ext3/ext4 文件系统 | 目录项的索引结构 |
| epoll(Linux) | 事件描述符的管理结构 |
| Nginx | 定时器管理的核心数据结构 |
红黑树之所以在这些关键基础设施中被广泛使用,正是因为它在查找效率和维护成本之间取得了良好的平衡:O(log n) 的操作保证加上较低的常数因子,使其成为通用平衡搜索树的首选。

浙公网安备 33010602011771号