算法导论13.2 Exercises 答案
13.2-1
算法的伪代码由RIGHT-ROTATE
给出,其和LEFT-ROTATE
非常类似。
1 | RIGHT-ROTATE(T, y) |
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)\)。