红黑树的概念
红黑树是一种自平衡的二叉搜索树。它在每个节点上增加了一个颜色位,可以是红色或黑色。通过对路径上节点颜色的约束,红黑树确保没有一条路径比其他路径长出两倍,从而保持近似平衡。
核心规则
- 每个节点要么是红色,要么是黑色。
- 根节点必须是黑色的。
- 如果一个节点是红色的,那么它的两个子节点都必须是黑色的(即不存在连续的红色节点)。
- 从任意节点到其所有叶子节点(NIL)的简单路径上,包含相同数量的黑色节点。
说明:在《算法导论》等经典著作中,通常补充了'每个叶子节点(NIL)都是黑色的'这一规则。这里的叶子节点指的是空指针(外部结点),实际编码实现时通常用 nullptr 表示,理解概念即可。
为什么最长路径不超过最短路径的 2 倍?
由规则 4 可知,从根到 NIL 节点的每条路径都有相同数量的黑色节点。极端情况下,最短路径是全为黑色节点的路径,假设长度为 bh(black height)。
由规则 2 和规则 3 可知,任意路径不会有连续红色节点。极端情况下,最长路径是一黑一红交替组成,长度约为 2 * bh。
综合来看,假设任意路径长度为 h,则满足 bh <= h <= 2 * bh。这种结构保证了树的高度始终保持在对数级别。
效率分析
假设 N 是节点数量,h 是最短路径长度,则有:
2^h - 1 <= N <= 2^(2*h) - 1
由此推出 h ≈ logN。红黑树增删查改的最坏情况是走最长路径 2*logN,时间复杂度仍为 O(logN)。
相比 AVL 树,红黑树的表达更抽象一些。AVL 树通过高度差直观控制平衡,而红黑树通过颜色约束间接实现近似平衡。两者效率处于同一档次,但红黑树在插入操作时的旋转次数更少,因为它对平衡的控制没那么严格,更适合频繁插入的场景。
红黑树的实现
结构定义
为了支持平衡调整,节点结构中需要加入父指针。以下是基于 key/value 对的模板定义:
// 枚举值表示颜色
enum Colour {
RED,
BLACK
};
// 红黑树节点模板
template<class K, class V>
struct RBTreeNode {
pair<K, V> _kv;
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent; // 更新控制平衡需要加入 parent 指针
Colour _col;
RBTreeNode(const pair<K, V>& kv)
:_kv(kv), _left(), _right(), _parent() {}
};
< , >
{
RBTreeNode<K, V> Node;
:
:
Node* _root = ;
};


