算法导论13.2 Exercises 答案

13.2-1

算法的伪代码由RIGHT-ROTATE给出,其和LEFT-ROTATE非常类似。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RIGHT-ROTATE(T, y)
x = y.left
y.left = x.right
if x.right != T.nil
x.right.p = y
x.p = y.p
if y.p == T.nil
T.root = x
else if y == y.p.left
y.p.left = x
else
y.p.right = x
x.right = y
y.p = x

13.2-2

对于任意一个节点$x$,如果它有右子节点$r$,那么可以进行左旋,从而将$r$旋转到$x$的位置;如果它有左子节点$l$,那么可以进行右旋,将$l$旋转到$x$的位置。

可见,如果当前节点$x$能够进行旋转,关键在于看它是否包含左/右子节点。只要包含一个子节点就能进行一次旋转。如果$x$拥有一个子节点,那么$x$恰好就需要一条边连接着它,这恰好对应了某一个旋转方案。

由于$T$中一共有$n-1$条边,因此$T$中有$n-1$种不同的旋转方式。

13.2-3

由图可以得知,$a$的深度增加了$1$;$b$的深度保持不变;$c$的深度减少了$1$。

13.2-4

对于任意一棵树$T$,考虑按照如下策略将其旋转成一条向右伸展的链$R$:从根节点出发,一直访问右子节点,直到最右侧的节点,得到一条路径$P=(v_1,v_2,\dots,v_m)$。如果这条路径上存在一个节点$x$,其左子节点非空,那么对$x$进行一次右旋,那么路径$P$将会增加一个节点。

当路径$P$包含了全部节点时,上述右旋过程结束。由于进行一次右旋操作,$P$就会增加一个节点,并且$T$中最多只有$n$个节点,因此最多$n-1$次右旋操作就可以将$T$旋转成$R$。

此外,由于右旋的操作是可逆的(对应一次左旋),因此从$R$旋转成任意一棵树同样至多只需要$n-1$次左旋操作。

那么,假设现在需要从$T$通过旋转操作变成$T’$,那么从$T$变换到$R$需要$c_1$次操作,从$R$变换到$T’$需要$c_2$次操作。那么总操作次数$c$满足$c\le c_1+c_2\le 2n-2$。因此$c=O(n)$,原结论成立。

$\star$ 13.2-5

如下如所示,左边的$T_1$无法通过右旋操作转化为$T_2$。

graph TD
  1((1))
  2((2))
  3(( ))
  4((1))
  5((2))
  6(( ))
  style 3 fill:#f100,stroke-width:0px
  style 6 fill:#f100,stroke-width:0px
  1---3
  1---2
  5---4
  5---6
  linkStyle 0 stroke:#0ff,stroke-width:0px 
  linkStyle 3 stroke:#0ff,stroke-width:0px

如果$T_1$能够只通过右旋操作转换成$T_2$,那么考虑进行递归操作。$T_2$的根节点必定在$T_1$中最左的路径上(即从根节点出发,一直访问左子节点,直到最左侧的叶节点,得到一条路径$P=(v_1,v_2,\dots,v_m)$)。因此,使用$O(n)$次的操作可以将这个根节点旋转到根的位置。那么接下来对这棵树的子树递归进行这种旋转操作。由于这棵树一共有$n$个节点,因此所需要的操作次数最多为$n\cdot O(n)=O(n^2)$。