AVL树初识
一、AVL树简介
AVL树是一种自平衡二叉搜索树(Binary Search Tree, BST),于1962年由Georgy Adelson-Velsky和Evgenii Landis提出,名字也来自他们两位的姓氏首字母组合。它通过在插入、删除节点后维持平衡性,确保在查找、插入、删除操作上保持 O ( log n ) O(\log n) O(logn) 的平均和最坏时间复杂度。
二、AVL树的平衡条件
在普通的二叉搜索树中,树的高度可能因为插入或删除导致严重失衡,从而退化成链表。而AVL树通过维护**平衡因子(Balance Factor)**来保持平衡。
平衡因子的定义:
平衡因子 = 左子树的高度 − 右子树的高度 \text{平衡因子} = \text{左子树的高度} - \text{右子树的高度} 平衡因子=左子树的高度−右子树的高度
- 平衡因子的绝对值不超过1(即 − 1 -1 −1、0、1),则该节点视为平衡。
- AVL树要求所有节点的平衡因子绝对值 ≤ 1 \leq 1 ≤1。
通过对节点的平衡因子进行检查和旋转操作,AVL树能始终维持其平衡性。
三、AVL树的基本操作
1. 查找(Search)
AVL树本质上是二叉搜索树,查找过程与普通二叉搜索树相同,时间复杂度为 O ( log n ) O(\log n) O(logn)。
2. 插入(Insert)
插入新节点的过程包括以下步骤:
- 常规插入: 按照二叉搜索树的规则插入新节点。
- 更新平衡因子: 从插入位置向上回溯,更新祖先节点的高度或平衡因子。
- 检测并恢复平衡: 如果某节点的平衡因子绝对值超过1,根据具体情况执行旋转操作。
插入导致的失衡类型
类型 | 条件 | 解决方法 |
---|---|---|
LL失衡 | 节点的平衡因子为 +2,且左子节点的平衡因子 ≥ 0 \geq 0 ≥0 | 单右旋 |
LR失衡 | 节点的平衡因子为 +2,且左子节点的平衡因子 < 0 < 0 <0 | 先左旋后右旋 |
RR失衡 | 节点的平衡因子为 -2,且右子节点的平衡因子 ≤ 0 \leq 0 ≤0 | 单左旋 |
RL失衡 | 节点的平衡因子为 -2,且右子节点的平衡因子 > 0 > 0 >0 | 先右旋后左旋 |
3. 删除(Delete)
删除操作分以下几种情况:
-
删除叶子节点或单子节点:
- 直接删除节点或用子节点替换。
-
删除有两个子节点的节点:
- 找出该节点的前驱或后继节点,用其值覆盖当前节点,并递归删除前驱/后继节点。
-
更新并恢复平衡:
- 从被删除节点的位置向上回溯,更新祖先节点的平衡因子,若失衡则执行旋转操作。
四、旋转操作
AVL树通过旋转操作调整树的结构,从而恢复平衡。旋转分为以下四种:
1. 单右旋(LL失衡)
- 触发条件:节点的平衡因子为 +2,且左子节点的平衡因子 ≥ 0 \geq 0 ≥0。
- 示例:
A B/ \ / \B α => 右旋 C A/ \ / / \C β γ β α
2. 先左旋后右旋(LR失衡)
- 触发条件:节点的平衡因子为 +2,且左子节点的平衡因子 < 0 < 0 <0。
- 示例:
A A C/ \ => 左旋 / \ => 右旋 / \B α B α C A\ / \ / \C B γ β α/ \ / \ β γ β γ
3. 单左旋(RR失衡)
- 触发条件:节点的平衡因子为 -2,且右子节点的平衡因子 ≤ 0 \leq 0 ≤0。
- 示例:
A B/ \ / \α B => 左旋 A C/ \ / \β C α β
4. 先右旋后左旋(RL失衡)
- 触发条件:节点的平衡因子为 -2,且右子节点的平衡因子 > 0 > 0 >0。
- 示例:
A A C/ \ => 右旋 / \ => 左旋 / \α B α C A B/ \ \ / \C γ B α β/ \ / \β γ β γ
五、时间复杂度与特性
- 高度: AVL树的高度保持在 O ( log n ) O(\log n) O(logn) 量级,最坏情况下的高度为 log ϕ ( n ) \log_{\phi}(n) logϕ(n)( ϕ \phi ϕ 为黄金比例,约为1.618)。
- 查找: 时间复杂度为 O ( log n ) O(\log n) O(logn)。
- 插入/删除: 时间复杂度为 O ( log n ) O(\log n) O(logn)。
- 额外空间: 需要维护每个节点的高度或平衡因子信息。
六、AVL树优缺点
优点:
- 查找性能优秀,适用于查找频繁的场景。
- 平衡性好,树的高度始终接近最优。
缺点:
- 插入和删除操作需要额外的旋转和更新,性能开销相对红黑树更高。
- 实现复杂,逻辑较为繁琐。
七、示例
以下为插入数据的过程示例:
插入数据:10, 20, 5, 15, 25, 30
- 插入
10
:
10
- 插入
20
:
10\20
- 插入
5
:
10/ \5 20
- 插入
15
:
10/ \5 20/15
- 插入
25
:
10/ \5 20/ \15 25
- 插入
30
,触发RR失衡,左旋后结果:
20/ \10 25/ \ \5 15 30
八、总结
AVL树是一种高效的自平衡二叉搜索树,适用于对查找效率要求较高的场景,但在插入删除频繁的情况下,其复杂度和性能可能略逊于红黑树。