2

问题:为什么 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。


adam1q84
1.7k 声望244 粉丝

GitHub 首页:[链接]