C++ 红黑树详解:原理、旋转与完整实现

1. 初识红黑树
红黑树本质上是一棵二叉搜索树,其每个结点会增加一个存储位(颜色),用于表示结点的颜色(红色或黑色)。通过对任何一条从根到叶子的路径上各个结点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出 2 倍,因而是近似平衡的。
这意味着红黑树的插入时间复杂度不存在最坏情况,稳定为 O(log n)。
2. 红黑树的规则
2.1 四条核心规则
- 每个结点要么是红色,要么是黑色。
- 根结点是黑色的。
- 所有叶子结点(NIL)都是黑色的。
- 如果一个结点是红色的,则它的两个子结点都是黑色的(即不能有两个连续的红色结点)。
- 对每个结点,从该结点到其所有后代叶子结点的简单路径上,均包含相同数目的黑色结点。
说明:《算法导论》等书籍中补充了每条路径黑色结点数量相同的规则。这里的叶子结点指的是空节点(NIL),而非传统意义上的终端结点。
2.2 为什么最长路径不超过最短路径的 2 倍?
- 最短路径:由规则 5 可知,从根到 NULL 结点的每条路径都有相同数量的黑色结点。极端场景下,最短路径就是全是黑色结点的路径,假设长度为 bh(black height)。
- 最长路径:由规则 2 和规则 3 可知,任意一条路径不会有连续的红色结点。极端场景下,最长路径就是一黑一红间隔组成,长度约为 2 * bh。
- 结论:综合红黑树的规则,理论上的全黑最短路径和一黑一红的最长路径并不是在每棵红黑树都所存在的。假设任意一条从根到 NULL 结点路径的长度为 h,那么 bh <= h <= 2 * bh。
2.3 效率分析
假设 N 是红黑树中结点数量,h 是最短路径的长度,那么 2^h - 1 <= N < 2^(2 * h) - 1,由此推出 h ≈ log N。这意味着红黑树增删查改最坏情况也就是走最长路径 2*log N,时间复杂度依然是 O(log N)。
红黑树的表达相对 AVL 树要抽象一些。AVL 树通过高度差严格控制平衡,而红黑树通过颜色约束间接实现近似平衡。两者效率在同一档次,但相对而言,插入相同数量的结点,红黑树的旋转次数更少。因为红黑树对平衡的控制没那么严格,实践中红黑树用得比 AVL 树多。
3. 红黑树的实现
3.1 结构定义
我们用枚举值来表示颜色,并定义节点结构。
enum Color { BLACK, RED };
template<class K, class V>
struct RBTreeNode {
pair<K, V> _kv;
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
Color _col;
RBTreeNode(const pair<K, V>& kv) :_kv(kv), _left(nullptr), _right(nullptr), _parent(), _col(RED) {}
};


