3-4 红黑树

红黑树(Red-Black Tree)

红黑树(Red-Black Tree)是一种自平衡二叉搜索树(Self-Balancing Binary Search Tree)。每个节点额外存储一个颜色属性(红色或黑色),通过颜色约束来保证树的高度近似平衡,从而确保查找、插入、删除等操作的时间复杂度均为 O(log n)。

红黑树在实际工程中应用广泛:

  • C++ 标准库中的 std::mapstd::set
  • Java 中的 TreeMapTreeSet
  • Linux 内核的进程调度器(CFS, Completely Fair Scheduler)
  • ext3/ext4 文件系统中的目录索引

与 AVL 树(AVL Tree)相比,红黑树的平衡条件更加宽松,插入和删除时需要的旋转操作更少,因此在写入频繁的场景下性能更优。


红黑树的性质

红黑树必须满足以下五条性质:

  1. 每个节点不是红色就是黑色 — 节点的颜色只能是这两种之一。
  2. 根节点是黑色 — 树的根节点必须为黑色。
  3. 每个叶子节点(NIL 节点)是黑色 — 这里的叶子指的是空节点(NIL),而不是含有数据的节点。
  4. 红色节点的两个子节点必须是黑色 — 不能有两个连续的红色节点(即从根到叶子的路径上不会出现两个相邻的红色节点)。
  5. 从任意节点到其每个叶子节点的所有路径都包含相同数目的黑色节点 — 这条性质保证了树的高度平衡。

其中性质 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 = 0BLACK = 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,逻辑与其他语言版本完全一致。


插入操作

红黑树的插入分为两步:

  1. 标准 BST 插入 — 按照二叉搜索树的方式找到插入位置,新节点颜色设为红色。
  2. 修复违规(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) 的操作保证加上较低的常数因子,使其成为通用平衡搜索树的首选。

posted @ 2026-04-16 11:11  游翔  阅读(14)  评论(0)    收藏  举报