AVL树(Adelson-Velsky and Landis Tree)是一种自平衡二叉搜索树。在AVL树中,任何节点的两个子树的高度最大差别为1。
为了衡量平衡,引入平衡因子(Balance Factor, 简称BF) : 平衡因子 = 左子树高度 - 右子树高度 在正常AVL树中,所有节点的平衡因子只能是 1、0 或 -1。如果插入或删除节点后,某个节点的平衡因子变成了 2 或 -2,树就失衡了,必须通过旋转来恢复平衡。
根据插入节点相对于失衡节点的位置,失衡分为四种情况,对应四种旋转方法:LL型、RR型、LR型、RL型。
为了方便理解图解,图中的代号说明如下:
- A:最早发现失衡的节点(平衡因子变为 2 或 -2)。
- B、C:A的子节点或孙节点。
- T1、T2、T3、T4:代表高度相等的子树(可以是空树)。
- 括号里的数字代表该节点的平衡因子。
1. LL型失衡:单右旋 (Right Rotation)
场景:在节点 A 的左孩子 (L) 的左子树 (L) 中插入了新节点,导致 A 的平衡因子变成 2。 口诀:左左节点,向右单旋。
操作方法: 将 B 向上提,A 向下压,A 变成 B 的右孩子。如果 B 原来有右子树(T2),则将 T2 挂到 A 的左边。
图文演示:
【旋转前 (LL型)】 【单右旋后 (恢复平衡)】
A(2) B(0)
/ \ / \
B(1) T4 --------> C(0) A(0)
/ \ (绕A向右旋转) / \ / \
C(0) T2 T0 T1 T2 T4
/ \
T0 T1
(插入的新节点在C下面)
原理解释:因为这是一棵二叉搜索树,大小关系是:C < B < T2 < A < T4。旋转后,B 成为根节点,左边是更小的 C,右边是更大的 A。原本属于 B 右边且小于 A 的 T2,正好可以放在 A 的左边。
2. RR型失衡:单左旋 (Left Rotation)
场景:在节点 A 的右孩子 (R) 的右子树 (R) 中插入了新节点,导致 A 的平衡因子变成 -2。这是 LL 型的镜像。 口诀:右右节点,向左单旋。
操作方法: 将 B 向上提,A 向下压,A 变成 B 的左孩子。如果 B 原来有左子树(T2),则将 T2 挂到 A 的右边。
图文演示:
【旋转前 (RR型)】 【单左旋后 (恢复平衡)】
A(-2) B(0)
/ \ / \
T1 B(-1) --------> A(0) C(0)
/ \ (绕A向左旋转) / \ / \
T2 C(0) T1 T2 T3 T4
/ \
T3 T4
(插入新节点)
原理解释:大小关系是:T1 < A < T2 < B < C。旋转后 B 做根节点,左边是比它小的 A,右边是比它大的 C。T2 大于 A 且小于 B,正好挂在 A 的右孩子位置。
3. LR型失衡:先左旋再右旋 (Left-Right Rotation)
场景:在节点 A 的左孩子 (L) 的右子树 (R) (即节点 C) 中插入了新节点,导致 A 的平衡因子变成 2。 注意:此时如果直接对 A 进行单右旋,树依然是不平衡的。必须经过两次旋转。
操作方法:
- 第一步(转为LL型) :先对 A 的左孩子 B 进行一次单左旋,把 C 提上来,B 压下去。此时树结构变成了 LL 型。
- 第二步(恢复平衡) :再对 A 进行一次单右旋,把 C 提上来充当新的根节点,A 压下去。
图文演示:
【状态1:LR型失衡】 【状态2:转换为LL型】 【状态3:最终平衡】
A(2) A(2) C(0)
/ \ / \ / \
B(-1) T4 --左旋B--> C(1) T4 --右旋A--> B(0) A(0)
/ \ / \ / \ / \
T1 C(0) B(0) T3 T1 T2 T3 T4
/ \ / \
T2 T3 T1 T2
(新节点在T2/T3中)
原理解释:大小关系是 T1 < B < T2 < C < T3 < A < T4。C 大小介于 B 和 A 之间。所以最终的形态必须是 C 在中间做父节点,B 在左边,A 在右边。C 原来的左子树 T2 挂给 B 做右孩子,右子树 T3 挂给 A 做左孩子。
4. RL型失衡:先右旋再左旋 (Right-Left Rotation)
场景:在节点 A 的右孩子 (R) 的左子树 (L) (即节点 C) 中插入了新节点,导致 A 的平衡因子变成 -2。这是 LR 型的镜像。
操作方法:
- 第一步(转为RR型) :先对 A 的右孩子 B 进行一次单右旋,把 C 提上来,B 压下去。此时树结构变成了 RR 型。
- 第二步(恢复平衡) :再对 A 进行一次单左旋,把 C 提上来,A 压下去。
图文演示:
【状态1:RL型失衡】 【状态2:转换为RR型】 【状态3:最终平衡】
A(-2) A(-2) C(0)
/ \ / \ / \
T1 B(1) --右旋B--> T1 C(-1) --左旋A--> A(0) B(0)
/ \ / \ / \ / \
C(0) T4 T2 B(0) T1 T2 T3 T4
/ \ / \
T2 T3 T3 T4
原理解释:大小关系是 A < C < B。最终形态 C 作为父节点,A 作为左子树,B 作为右子树。C 原本的左边 T2 挂在 A 的右边,右边 T3 挂在 B 的左边。
总结与记忆诀窍
-
看名字知步骤:
- LL 和 RR 是直线型,只需要一次单旋(方向与名字相反:LL右旋,RR左旋)。
- LR 和 RL 是折线型,需要两次旋转。名字本身就是旋转方向:LR = 先左旋再右旋;RL = 先右旋再左旋。
-
核心原则(二叉搜索树特性不变) : 无论怎么转,中序遍历(Left -> Root -> Right)的结果绝对不能改变。旋转的本质就是把高度较低的一侧往下压,把高度较高的一侧提上来,同时把断开的子树重新挂载到合适的大小区间位置。