问题:为什么 AVL 树只需要 LL,LR,RR,RL 四种旋转?
首先说明一下本文所使用的记号:
T(N):以节点 N 为根的树
L(T)、R(T):树T的左右子树
H(T):树T的高度
DH(T):左右子树高度之差,即 H(R(T)) - H(L(T))
|DH(T)|:左右子树高度之差的绝对值
需要旋转的两种情况
给定一棵树 T(1)(当然,它可能也是其它树的子树,不过这不影响讨论),根据 AVL 对「平衡」的定义(|DH(T)| < 2),只有当树 T(1) 处于如下两种情况时,才需要旋转(注意:|DH(T(1))| 不可能 > 2):
1. DH(T(1)) == -2
1
/ \
2(n+2) 3(n)
2. DH(T(1)) == 2
1
/ \
2(n) 3(n+2)
再说明一下标记,上面 1、2、3 这些数字,表示树的节点;3(n+2) 表示以节点 3 为根的子树高度为n+2。
现在,以 DH(T(1)) == -2 为例,就【插入】和【删除】两种操作分别加以讨论。而 DH(T(1)) == 2 的情况与此类似,不再赘述。
插入
插入之前的 T(1)
如果 DH(T(1)) == -2 是由【插入】引起的,则插入之前的 T(1) 应为:
DH(T(1)) == -1
1
/ \
2(n+1) 3(n)
展开为:
1
/ \
2(n+1) 3(n)
/ \
4(?) 5(?)
T(4),T(5) 的高度可取值如下:
H(T(4)) H(T(5))
a. n n
b. n n-1
c. n-1 n
但 b, c 其实都不可能。比如 b,要使 DH(T(1)) == -2,只能插入节点到 T(4),而一旦这样插入了,又会使 DH(T(2)) == -2 了。所以插入之前的 T(1) 应为:
1
/ \
2(n+1) 3(n)
/ \
4(n) 5(n)
插入节点到 T(4) 的情况
如下图。旋转也一并给出,记这种旋转为 rotate1(其实就是 LL)。
1
/ \
2 3(n)
/ \
4(n+1) 5(n)
rotate1:
2
/ \
/ 1
/ / \
4(n+1) 5(n) 3(n)
插入节点到 T(5) 的情况
1
/ \
2 3(n)
/ \
4(n) 5(n+1)
如何旋转以达到平衡,并不明显。必须将节点 5 进一步展开来看:
1
/ \
2 3(n)
/ \
4(n) 5(n+1)
/ \
6(?) 7(?)
T(6),T(7) 的高度可取值如下:
H(T(6)) H(T(7))
a. n n
b. n n-1
c. n-1 n
但 a 不可能。否则,在新节点插入之前,H(T(5))就已经为 n+1,而 T(1) 就已经不平衡了。
b, c 都有可能。如果是 b,新节点插入到 T(6);如果是 c,新节点插入到 T(7)。所以插入节点到T(5) 的情形最终应该是:
1
/ \
2 3(n)
/ \
4(n) 5(n+1)
/ \
6(n/n-1) 7(n-1/n)
rotate2:
5
/ \
2 1
/ \ / \
4(n) 6 7 3(n)
rotate2 其实就是 LR。
关于【插入】的小结
总结一下,对于【插入】,有如下 2种旋转:
1
/ \
2 3(n)
/ \
4(n+1) 5(n)
rotate1:
2
/ \
/ 1
/ / \
4(n+1) 5(n) 3(n)
1
/ \
2 3(n)
/ \
4(n) 5
/ \
6(n/n-1) 7(n-1/n)
rotate2:
5
/ \
2 1
/ \ / \
4(n) 6 7 3(n)
删除
删除之前的 T(1)
如果 DH(T(1)) == -2 是由【删除】引起的,则删除之前的 T(1) 应为:
DH(T(1)) == -1
1
/ \
2(n+2) 3(n+1)
展开为:
1
/ \
2 3(n+1)
/ \
4(?) 5(?)
T(4),T(5) 的高度可取值如下:
H(T(4)) H(T(5))
a. n+1 n+1 - DH(T(2)) : 0
b. n+1 n - DH(T(2)) : -1
c. n n+1 - DH(T(2)) : 1
这三种都有可能,所以删除之前的 T(1) 为:
A.
1
/ \
2 3(n+1)
/ \
4(n+1) 5(n+1/n)
B.
1
/ \
2 3(n+1)
/ \
4(n) 5(n+1)
对于 T(1) A 的旋转
对于 T(1) A,从子树 T(3) 删除节点而使 H(T(3)) 减 1 后,得到需要旋转的树如下:
1
/ \
2 3(n)
/ \
4(n+1) 5(n+1/n)
rotate1:
2
/ \
/ 1
/ / \
4(n+1) 5(n+1/n) 3(n)
旋转也一并给出。同样还是 rotate1。
对于 T(1) B 的旋转
对于 T(1) B,从子树 T(3) 删除节点而使 H(T(3)) 减 1 后,得到需要旋转的树如下:
1
/ \
2 3(n)
/ \
4(n) 5(n+1)
如何旋转以达到平衡,并不明显。须将节点 5 进一步展开来看:
1
/ \
2 3(n)
/ \
4(n) 5
/ \
6(?) 7(?)
T(6),T(7) 的高度可取值如下:
H(T(6)) H(T(7))
n n
n n-1
n-1 n
这三种都有可能。所以 T(1) B 的情形最终为:
1
/ \
2 3(n)
/ \
4(n) 5
/ \
6(n/n/n-1) 7(n/n-1/n)
rotate2:
5
/ \
2 1
/ \ / \
4(n) 6 7 3(n)
旋转还是 rotate2。
关于【删除】的小结
总结一下,对于【删除】,有如下 2 种旋转:
1
/ \
2 3(n)
/ \
4(n+1) 5(n+1/n)
rotate1:
2
/ \
/ 1
/ / \
4(n+1) 5(n+1/n) 3(n)
1
/ \
2 3(n)
/ \
4(n) 5
/ \
6(n/n/n-1) 7(n/n-1/n)
rotate2:
5
/ \
2 1
/ \ / \
4(n) 6 7 3(n)
结论
对于 DH(T(1)) == -2,共有 2 种旋转,如上 rotate1 和 rotate2。虽然对于【插入】和【删除】,旋转时平衡点的调整更新可能会有所不同,但其旋转的方式是一致的。
最后,rotate1 即所谓的 LL,rotate2 即所谓的 LR。如果再去分析 DH(T(1)) == 2 的话,同理可以得到 RR 和 RL。