C++ 伸展树与红黑树详解及核心实现
在平衡二叉搜索树(BBST)的家族中,伸展树和红黑树是两种极具代表性的结构。它们各有侧重:伸展树利用局部性原理优化频繁访问的场景,而红黑树则通过颜色约束确保稳定的最坏时间复杂度,是 C++ STL 中 std::map、std::set 等容器的底层基石。
1. 伸展树介绍
伸展树(Splay Tree)是一种自调整的二叉搜索树,由 John Edward Hopcroft 和 Robert Endre Tarjan 于 1985 年提出。与 AVL 树不同,它不追求严格的平衡,而是通过'伸展'操作将最近访问的节点移动到根节点,从而让热点数据更容易被访问。
1.1 旋转策略
每次访问(搜索、插入或删除)一个节点时,都会执行一次'伸展'过程。这通常涉及三种旋转模式:
- 单旋转 (Zig):当被访问节点的父节点是根节点时执行。直接将该节点旋转到根位置。
- 一字形旋转 (Zig-Zig):当被访问节点与其父节点、祖父节点处于同侧(如左 -左或右 -右)时执行。先围绕父节点旋转,再围绕祖父节点旋转,将节点上移两层。
- 之字形旋转 (Zig-Zag):当被访问节点与其父节点、祖父节点形成折线(如左 -右或右 -左)时执行。先围绕父节点旋转,再围绕祖父节点旋转,同样将节点上移两层。
这种机制使得频繁访问的节点始终靠近根部,虽然单次操作可能耗时 O(n),但在 m >= n 次操作的序列中,均摊时间复杂度为 O(log n)。
1.2 算法逻辑
// 伪代码示意:将节点 s 伸展至根
void splaying(Node* s) {
while (s->parent != nullptr) {
Node* p = s->parent;
if (p->parent == nullptr) {
// 情况 1: 单旋转
rotate(p);
} else {
Node* g = p->parent;
// 判断形状决定一字形或之字形
if ((p->left == s && g->left == p) || (p->right == s && g->right == p)) {
rotate(g); // 一字形双旋第一步
rotate(p); // 一字形双旋第二步
} else {
rotate(p); // 之字形双旋第一步
rotate(g); // 之字形双旋第二步
}
}
}
}
2. 红黑树介绍
红黑树是一棵二叉搜索树,每个节点增加了一个存储位表示颜色(红色或黑色)。通过对路径颜色的约束,确保没有一条路径比其他路径长出一倍以上。


