AVL
AVL 树(以发明者 Adelson-Velsky 和 Landis 命名)是计算机科学中第一种自平衡二叉搜索树。
它在 BST 的基础上增加了一个硬性条件:任何节点的两个子树的高度差(平衡因子)最多为 1。
1. 核心概念:平衡因子 (Balance Factor)
对于 AVL 树中的任何节点 $N$,其平衡因子定义为:
$$BF(N) = Height(LeftSubtree) - Height(RightSubtree)$$
- $BF = 0$:左右完全平衡。
- $BF = 1$ 或 $-1$:轻微倾斜,但仍被视为平衡。
- $BF > 1$ 或 $< -1$:失去了平衡,需要通过旋转来修复。
2. 四种旋转方式
当我们在 AVL 树中插入或删除节点导致失衡时,会根据失衡的形态采取四种不同的旋转操作:
1. 左左型 (LL) -> 右旋 (Right Rotation)
插入点位于左子树的左侧。
2. 右右型 (RR) -> 左旋 (Left Rotation)
插入点位于右子树的右侧。
3. 左右型 (LR) -> 先左旋再右旋
插入点位于左子树的右侧。先对左子树进行左旋,变成 LL 型,再进行一次右旋。
4. 右左型 (RL) -> 先右旋再左旋
插入点位于右子树的左侧。先对右子树进行右旋,变成 RR 型,再进行一次左旋。
3. AVL 树的 C++ 实现
AVL 树的代码比普通 BST 复杂,因为每次插入后都需要更新高度并回溯检查平衡。
C++
#include <iostream>
#include <algorithm>
using namespace std;
struct Node {
int val;
int height; // 记录高度以计算平衡因子
Node *left, *right;
Node(int v) : val(v), height(1), left(nullptr), right(nullptr) {}
};
class AVLTree {
public:
Node* root = nullptr;
// 获取高度的辅助函数
int getHeight(Node* n) { return n ? n->height : 0; }
// 计算平衡因子
int getBalance(Node* n) { return n ? getHeight(n->left) - getHeight(n->right) : 0; }
// 右旋转 (LL)
Node* rotateRight(Node* y) {
Node* x = y->left;
Node* T2 = x->right;
x->right = y;
y->left = T2;
y->height = max(getHeight(y->left), getHeight(y->right)) + 1;
x->height = max(getHeight(x->left), getHeight(x->right)) + 1;
return x;
}
// 左旋转 (RR)
Node* rotateLeft(Node* x) {
Node* y = x->right;
Node* T2 = y->left;
y->left = x;
x->right = T2;
x->height = max(getHeight(x->left), getHeight(x->right)) + 1;
y->height = max(getHeight(y->left), getHeight(y->right)) + 1;
return y;
}
// 递归插入
Node* insert(Node* node, int val) {
if (!node) return new Node(val);
if (val < node->val) node->left = insert(node->left, val);
else if (val > node->val) node->right = insert(node->right, val);
else return node; // 不允许重复值
// 1. 更新当前节点高度
node->height = 1 + max(getHeight(node->left), getHeight(node->right));
// 2. 获取平衡因子并检查是否失衡
int balance = getBalance(node);
// LL 情况
if (balance > 1 && val < node->left->val) return rotateRight(node);
// RR 情况
if (balance < -1 && val > node->right->val) return rotateLeft(node);
// LR 情况
if (balance > 1 && val > node->left->val) {
node->left = rotateLeft(node->left);
return rotateRight(node);
}
// RL 情况
if (balance < -1 && val < node->right->val) {
node->right = rotateRight(node->right);
return rotateLeft(node);
}
return node;
}
void inorder(Node* n) {
if (!n) return;
inorder(n->left);
cout << n->val << " ";
inorder(n->right);
}
};
4. AVL 树 vs 红黑树 (Red-Black Tree)
在实际应用中,你可能经常听到这两者的对比:
| 特性 | AVL 树 | 红黑树 |
|---|---|---|
| 平衡程度 | 严格平衡 (高度差 $\le 1$) | 弱平衡 (最长路径不超最短两倍) |
| 查找性能 | 更好 (因为树更矮) | 稍逊 |
| 插入/删除性能 | 较慢 (可能涉及多次旋转) | 更好 (旋转次数少) |
| 适用场景 | 查找频繁、插入删除少的场景 | 插入删除频繁的场景 (如 C++ STL, Java HashMap) |
浙公网安备 33010602011771号