12.1 什么是二叉搜索树
12.1-1
高度为 2:
高度为3:
高度为4:
高度为5:
高度为6:
12.1-2
解:最小堆的结点值总不大于孩子结点的值,而二叉搜索树的结点值不小于左子树元素结点的值,不大于右子树元素结点的值;最小堆性质无法在O(n)时间内按序输出一棵有n个结点树的关键字,因为堆(以最小堆为例)无法告知大于当前结点的最小元素是在左子树还是在右子树。
换一个角度考虑,如果真的有这种方法,意味着存在O(n)时间的比较排序算法,而这被证明是不存在的。
12.1-3
解:
INORDER-TREE-WALK(T)
let S be an empty stack
current = T.root
done = 0
while !done
if current != NIL
PUSH(S, current)
current = current.left
else
if !S.EMPTY()
current = POP(S)
print current
current = current.right
else done = 1
12.1-4
解:
PREORDER-TREE-WALK(x)
if x != NIL
print x.key
PREORDER-TREE-WALK(x.left)
PREORDER-TREE-WALK(x.right)
POSTORDER-TREE-WALK(x)
if x != NIL
POSTORDER-TREE-WALK(x.left)
POSTORDER-TREE-WALK(x.right)
print x.key
递归真的好用。
12.1-5
证明:反证法,假设我们可以使用小于 Ω ( n lg n ) \Omega(n\lg n) Ω(nlgn)的时间,因为遍历二叉搜索树只需要 Θ ( n ) \Theta(n) Θ(n),我们就可以得到小于 Ω ( n lg n ) \Omega(n\lg n) Ω(nlgn)的比较排序算法,这与第8章的证明相矛盾。(也就类似于12.1-3的思路了)
12.2 查询二叉搜索树
12.2-1
解:c(先找到911后找到912不可能)和e(先找到347后找到299不可能)。
12.2-2
解:
TREE-MINIMUM(x)
while x.left != NIL
return TREE-MINIMUM(x.left)
return x
TREE-MAXIMUM(x)
while x.right != NIL
return TREE-MAXIMUM(x.right)
return x
12.2-3
解:
TREE-PREDECESSOR(x)
if x.left != NIL
return TREE-MAXIMUM(x.left)
y = x.p
while y != NIL and x == y.left
x = y
y = y.p
return y
12.2-4
思路:例如在查找过程中某一结点x的右孩子的两个孩子结点选择了右边,x的右孩子的左孩子就归到A集合,但该数还是比B集合中的x大。
12.2-5
证明:结点x的后继s一定位于x的右子树,而后继s如果有左孩子,该左孩子肯定还是位于x的右子树,那么该左孩子的值就介于x和s之间,那么s就不是x的后继了,矛盾;对称地可证明前驱没有右孩子。
12.2-6
证明:首先,我们确定 y y y必须是 x x x的祖先。如果 y y y不是 x x x的祖先,那么让 z z z表示 x x x和 y y y的第一个共同祖先。根据二叉搜索树属性, x < z < y x<z<y x<z<y,因此 y y y不能是 x x x的后继。接下来注意 y . l e f t y.left y.left必须是 x x x的祖先,因为如果不是,那么 y . r i g h t y.right y.right将是 x x x的祖先,暗示 x > y x> y x>y。最后,假设 y y y不是 x x x的最底层祖先,其左孩子也是 x x x的祖先。让 z z z表示这个最底层祖先。那么 z z z必须在 y y y的左子树中,这意味着 z < y z <y z<y,这与 y y y是 x x x的后继相矛盾。
12.2-7
证明(来自参考答案):
Note that a call to TREE-MINIMUM \text{TREE-MINIMUM} TREE-MINIMUM followed by n − 1 n - 1 n−1 calls to TREE-SUCCESSOR \text{TREE-SUCCESSOR} TREE-SUCCESSOR performs exactly the same inorder walk of the tree as does the procedure INORDER-TREE-WALK \text{INORDER-TREE-WALK} INORDER-TREE-WALK. INORDER-TREE-WALK \text{INORDER-TREE-WALK} INORDER-TREE-WALK prints the TREE-MINIMUM \text{TREE-MINIMUM} TREE-MINIMUM first, and by
definition, the TREE-SUCCESSOR \text{TREE-SUCCESSOR} TREE-SUCCESSOR of a node is the next node in the sorted order determined by an inorder tree walk.
This algorithm runs in Θ ( n ) \Theta(n) Θ(n) time because:
It requires O ( n ) O(n) O(n) time to do the n procedure calls.
It traverses each of the n − 1 n - 1 n−1 tree edges at most twice, which takes O ( n ) O(n) O(n) time.
To see that each edge is traversed at most twice (once going down the tree and once going up), consider the edge between any node u u u and either of its children, node v v v. By starting at the root, we must traverse ( u , v ) (u, v) (u,v) downward from u u u to v v v, before traversing it upward from v v v to u u u. The only time the tree is traversed downward is in code of TREE-MINIMUM \text{TREE-MINIMUM} TREE-MINIMUM, and the only time the tree is traversed upward is in code of TREE-SUCCESSOR \text{TREE-SUCCESSOR} TREE-SUCCESSOR when we look for the successor of a node that has no right subtree.
Suppose that is u u u's left child.
Before printing u u u, we must print all the nodes in its left subtree, which is rooted at v v v, guaranteeing the downward traversal of edge ( u , v ) (u, v) (u,v).
After all nodes in u u u's left subtree are printed, u u u must be printed next. Procedure TREE-SUCCESSOR \text{TREE-SUCCESSOR} TREE-SUCCESSOR traverses an upward path to u u u from the maximum element (which has no right subtree) in the subtree rooted at . This path clearly includes edge ( u , v ) (u, v) (u,v), and since all nodes in u u u's left subtree are printed, edge ( u , v ) (u, v) (u,v) is never traversed again.
Now suppose that v v v is u u u's right child.
After u u u is printed, TREE-SUCCESSOR ( u ) \text{TREE-SUCCESSOR}(u) TREE-SUCCESSOR(u) is called. To get to the minimum element in u u u's right subtree (whose root is v v v), the edge ( u , v ) (u, v) (u,v) must be traversed downward.
After all values in u u u's right subtree are printed, TREE-SUCCESSOR \text{TREE-SUCCESSOR} TREE-SUCCESSOR is called on the maximum element (again, which has no right subtree) in the subtree rooted at v v v. TREE-SUCCESSOR \text{TREE-SUCCESSOR} TREE-SUCCESSOR traverses a path up the tree to an element after u u u, since u u u was already printed. Edge ( u , v ) (u, v) (u,v) must be traversed upward on this path, and since all nodes in u u u's right subtree have been printed, edge ( u , v ) (u, v) (u,v) is never traversed again.
Hence, no edge is traversed twice in the same direction.
Therefore, this algorithm runs in Θ ( n ) \Theta(n) Θ(n) time.
12.2-8
证明:假设 x x x是起始节点, y y y是结束节点。 x x x和 y y y之间的距离最多为 2 h 2h 2h,连接 k k k节点的所有边都被访问两次,因此需要 O ( k + h ) O(k + h) O(k+h)时间。
12.2-9
证明:
假设 x x x是 y y y的左孩子,那么 y . k e y > x . k e y y.key>x.key y.key>x.key,以及 y y y可能有的右子树的关键字都大于 y . k e y y.key y.key,且 x x x是叶结点没有右孩子,所以 y . k e y y.key y.key是 T T T树中大于 x . k e y x.key x.key的最小关键字;
假设 x x x是 y y y的右孩子,那么 y . k e y < x . k e y y.key<x.key y.key<x.key,以及 y y y可能有的左子树的关键字都小于 y . k e y y.key y.key,且 x x x是叶结点没有左孩子,所以 y . k e y y.key y.key是 T T T树中小于 x . k e y x.key x.key的最大关键字。
12.3 插入和删除
12.3-1
解:
RECURSIVE-TREE-INSERT(T, z)
if T.root = NIL
T.root = z
else INSERT(NIL, T.root, z)
INSERT(p, x, z)
if x == NIL
z.p = p
if z.key < p.key
p.left = z
else
p.right = z
else if z.key < x.key
INSERT(x, x.left, z)
else
INSERT(x, x.right, z)
12.3-2
证明:易证路径是一样的,又因为搜索时检查的节点数也包括搜索到的节点,所以……
12.3-3
解:
TREE-SORT(A)
let T be an empty binary search tree
for i = 1 to A.length
TREE-INSERT(A[i])
INORDER-TREE-WALK(T.root)
最坏情况: Θ ( n 2 ) \Theta(n^2) Θ(n2) - 当重复的 TREE-INSERT \text {TREE-INSERT} TREE-INSERT操作产生一个线性结点链时。
最好情况: Θ ( n lg n ) \Theta(n\lg n) Θ(nlgn) - 当重复的 TREE-INSERT \text {TREE-INSERT} TREE-INSERT操作产生高度为 Θ ( lg n ) \Theta(\lg n) Θ(lgn)的二叉树时。
12.3-4
解:不一样
先删除A,再删除B:
A C C
/ \ / \ \
B D B D D
/
C
先删除B,再删除A:
A A D
/ \ \ /
B D D C
/ /
C C
12.3-5
解:
PARENT(z)
if z == NIL
m = T.root
else
m = z.left
while m != x
p = m
m = m.right
return p
GET-PARENT(T, x)
if x.right == NIL
if x == x.succ.left
x.p = x.succ
else
z = x.succ
x.p = PARENT(z)
else
y = TREE-MAXIMUM(x.right)
if x == y.succ.left
x.p = y.succ
else
z = y.succ
x.p = PARENT(z)
12.3-6
思路:可以在原函数第5行添加一个RANDOM(0,1),返回0选择前驱,返回1选择后继即可。
12.4 随机构建二叉搜索树
12.4-1
证明:
∑ i = 0 n − 1 ( i + 3 3 ) = ∑ i = 0 n − 1 ( i + 3 ) ( i + 2 ) ( i + 1 ) 6 = 1 6 ∑ i = 0 n − 1 i 3 + 6 i 2 + 11 i + 6 = 1 6 ( ( n − 1 ) 2 n 2 4 + 6 ( n − 1 ) n ( 2 n − 1 ) 6 + 11 n ( n − 1 ) 2 + 6 n ) = n ( n + 1 ) ( n + 2 ) ( n + 3 ) 24 = ( n + 3 4 ) . \begin{aligned} \sum_{i = 0}^{n - 1} \binom{i + 3}{3} & = \sum_{i = 0}^{n - 1} \frac{(i + 3)(i + 2)(i + 1)}{6} \\ & = \frac{1}{6} \sum_{i = 0}^{n - 1} i^3 + 6i^2 + 11i + 6 \\ & = \frac{1}{6} (\frac{(n - 1)^2 n^2}{4} + \frac{6(n - 1)n(2n - 1)}{6} + \frac{11n(n - 1)}{2} + 6n) \\ & = \frac{n(n + 1)(n + 2)(n + 3)}{24} \\ & = \binom{n + 3}{4}. \end{aligned} i=0∑n−1(3i+3)=i=0∑n−16(i+3)(i+2)(i+1)=61i=0∑n−1i3+6i2+11i+6=61(4(n−1)2n2+66(n−1)n(2n−1)+211n(n−1)+6n)=24n(n+1)(n+2)(n+3)=(4n+3).
12.4-2
证明(来自参考答案):
We will answer the second part first. We shall show that if the average depth of a p node is Θ ( lg n ) \Theta(\lg n) Θ(lgn), then the height of the tree is O ( n lg n ) O(n\lg n) O(nlgn). Then we will answer the first part by exhibiting that this bound is tight: there is a binary search tree with p average node depth Θ ( lg n ) \Theta(\lg n) Θ(lgn) and height Θ ( n lg n ) = ω ( lg n ) \Theta(\sqrt{n\lg n}) = \omega(\lg n) Θ(nlgn)=ω(lgn).
Lemma
If the average depth of p a node in an n n n-node binary search tree is Θ ( lg n ) \Theta(\lg n) Θ(lgn), then the height of the tree is O ( n lg n ) O(\sqrt{n\lg n}) O(nlgn).
Proof
Suppose that an