平衡二叉树(AVL树) 是一种自平衡的二叉搜索树(BST),由苏联数学家Adelson-Velsky和Landis于1962年发明(因此得名AVL)。其核心特性是:任意节点的左右子树高度差(平衡因子)绝对值不超过1。这种平衡特性确保了高效的查找、插入和删除操作,时间复杂度始终为 O(log n)
。
核心特性
-
平衡因子(Balance Factor)
每个节点的平衡因子 =左子树高度 - 右子树高度
取值范围:{-1, 0, 1}
示例:若节点左子树高度为3,右子树高度为2,则平衡因子=1(合法) -
自平衡机制
当插入或删除节点导致平衡因子超出±1范围时,树会自动通过旋转操作恢复平衡。
四种旋转操作(关键维护手段)
假设节点 A 失衡(|BF| > 1),根据失衡类型进行旋转:
- 左旋(LL型失衡)
A B
/ / \
B -> C A
/
C
场景:A的右子树过高(BF = -2)且右子节点B的BF ≤ 0
- 右旋(RR型失衡)
A B
\ / \
B -> A C
\
C
场景:A的左子树过高(BF = 2)且左子节点B的BF ≥ 0
- 左右旋(LR型失衡)
A A C
/ / / \
B -> C -> B A
\ /
C B
场景:A的左子树过高(BF=2),但左子节点B的BF = -1
步骤:
- 先对B左旋→转换为RR型
- 再对A右旋
- 右左旋(RL型失衡)
A A C
\ / / \
B -> C -> A B
/ \
C B
场景:A的右子树过高(BF=-2),但右子节点B的BF = 1
步骤:
- 先对B右旋→转换为LL型
- 再对A左旋
AVL树操作复杂度
操作 | 时间复杂度 | 说明 |
---|---|---|
查找 | O(log n) | 与普通BST相同 |
插入 | O(log n) | 需回溯至根节点并可能旋转 |
删除 | O(log n) | 同上,最多旋转O(1)次 |
旋转 | O(1) | 仅调整局部指针 |
AVL树 vs 红黑树
特性 | AVL树 | 红黑树 |
---|---|---|
平衡严格性 | 严格(高度差≤1) | 宽松(最长路径≤2倍最短) |
查找效率 | 更高(更严格的平衡) | 稍低 |
插入/删除 | 更频繁的旋转(维护成本高) | 旋转次数较少 |
适用场景 | 读密集型(如数据库索引) | 写密集型(如STL map) |
Java实现示例(插入与旋转)
class AVLNode {
int key, height;
AVLNode left, right;
AVLNode(int key) {
this.key = key;
this.height = 1; // 新节点高度为1
}
}
public class AVLTree {
private AVLNode root;
// 计算节点高度
private int height(AVLNode node) {
return (node == null) ? 0 : node.height;
}
// 计算平衡因子
private int balanceFactor(AVLNode node) {
return (node == null) ? 0 : height(node.left) - height(node.right);
}
// 右旋(RR型失衡)
private AVLNode rightRotate(AVLNode y) {
AVLNode x = y.left;
AVLNode T2 = x.right;
x.right = y;
y.left = T2;
// 更新高度
y.height = Math.max(height(y.left), height(y.right)) + 1;
x.height = Math.max(height(x.left), height(x.right)) + 1;
return x; // 返回新的根节点
}
// 左旋(LL型失衡)
private AVLNode leftRotate(AVLNode x) {
AVLNode y = x.right;
AVLNode T2 = y.left;
y.left = x;
x.right = T2;
x.height = Math.max(height(x.left), height(x.right)) + 1;
y.height = Math.max(height(y.left), height(y.right)) + 1;
return y;
}
// 插入节点(核心)
public AVLNode insert(AVLNode node, int key) {
// 1. 标准BST插入
if (node == null) return new AVLNode(key);
if (key < node.key)
node.left = insert(node.left, key);
else if (key > node.key)
node.right = insert(node.right, key);
else
return node; // 重复值不插入
// 2. 更新高度
node.height = 1 + Math.max(height(node.left), height(node.right));
// 3. 检查平衡因子并旋转
int balance = balanceFactor(node);
// RR型(左子树过高且新节点在左子树的左侧)
if (balance > 1 && key < node.left.key)
return rightRotate(node);
// LL型(右子树过高且新节点在右子树的右侧)
if (balance < -1 && key > node.right.key)
return leftRotate(node);
// LR型(左子树过高但新节点在左子树的右侧)
if (balance > 1 && key > node.left.key) {
node.left = leftRotate(node.left);
return rightRotate(node);
}
// RL型(右子树过高但新节点在右子树的左侧)
if (balance < -1 && key < node.right.key) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
return node;
}
}
应用场景
- 数据库索引:需快速查找(如B+树底层优化)
- 内存受限系统:高效存储有序数据
- 实时应用:保证最坏情况下的操作性能
关键总结:AVL树通过严格的平衡约束和旋转操作,在动态数据集中维持高效操作,是计算机科学中平衡树理论的基石之一。