C++ 红黑树设计与实现详解
前言
在深入平衡二叉搜索树的学习中,AVL 树让我们理解了高度平衡的重要性。而红黑树(Red-Black Tree)则是另一种更为实用且高效的平衡方案,它是 C++ STL 中 map 和 set 等容器的底层实现核心。相比 AVL 树严格的平衡要求,红黑树通过颜色标记来近似平衡,牺牲了部分查询效率换取了更少的旋转操作,从而在插入和删除场景下表现更佳。
1. 红黑树的概念
1.1 什么是红黑树
红黑树是一种自平衡的二叉搜索树。除了每个节点存储键值对外,它还增加了一个颜色属性,节点颜色只能是红色或黑色。通过对路径上节点颜色的约束,确保没有一条路径会比其他路径长出两倍,从而实现近似平衡。
1.2 红黑树的五条规则
- 每个节点不是红色就是黑色。
- 根节点必须是黑色。
- 如果一个节点是红色,则它的两个子节点必须是黑色(即不能有两个连续的红色节点)。
- 对于任意节点,从该节点到其所有叶子节点(NULL)的简单路径上,包含相同数目的黑色节点(称为黑高)。
- 所有的叶子节点(NULL)都是黑色的。
注:这里的叶子节点通常指空指针,而非传统意义上的终端节点。《算法导论》中常将 NULL 视为外部节点。
1.3 为什么最长路径不超过最短路径的两倍
根据规则 4,每条路径上的黑色节点数量(黑高 bh)是固定的。最短路径即为全黑节点路径,长度为 bh。由于规则 3 限制了红色节点不能连续出现,最长路径必然是红黑交替,长度约为 2bh。因此,红黑树的最长路径不会超过最短路径的两倍。
1.4 效率分析
假设节点数为 N,最短路径长度为 h。由 2^h - 1 <= N < 2^(2h) - 1 可知,h 约等于 logN。因此,红黑树的查找、插入、删除时间复杂度均为 O(logN)。虽然比 AVL 树略慢,但插入时的旋转次数更少,整体性能更优。
2. 红黑树的实现
2.1 节点结构
红黑树采用三叉链表结构,每个节点需要记录父节点、左右孩子以及颜色信息。默认新插入节点为红色。
enum Colour { RED, BLACK };
template<class K, class V>
struct RBTreeNode {
pair<K, V> _kv;
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
Colour _col;
RBTreeNode(const pair<K, V>& kv)
:_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED) {}
};
2.2 查找操作
红黑树的查找逻辑与二叉搜索树完全一致,利用 Key 进行比较,时间复杂度 O(logN)。
Node* Find(const K& key) {
Node* cur = _root;
(cur) {
(cur->_kv.first > key) {
cur = cur->_left;
} (cur->_kv.first < key) {
cur = cur->_right;
} {
cur;
}
}
;
}


