《算法导论》笔记 第12章 12.2 查询二叉查找树
【笔记】
对一棵高度为h的二叉查找树,动态集合操作SEARCH、MINIMUM、MAXIMUM、SUCCESSOR和PREDECESSOR等的运行时间均为O(h)。
NODE* treeSearch(NODE *rt,T k) { if (rt==NULL || k==rt->key) return rt; if (k<rt->key) return treeSearch(rt->l,k); else return treeSearch(rt->r,k); } NODE* iterativeTreeSearch(NODE *rt,T k) { while (rt!=NULL && k!=rt->key) { if (k<rt->key) rt=rt->l; else rt=rt->r; } } NODE* treeMinimum(NODE *rt) { while (rt->l!=NULL) rt=rt->l; return rt; } NODE* treeMaximum(NODE *rt) { while (rt->r!=NULL) rt=rt->r; return rt; } NODE* treeSuccessor(NODE *rt) { if (rt->r!=NULL) return treeMinimum(rt->r); NODE* pt=rt->p; while (pt!=NULL && rt==pt->r) { rt=pt; pt=pt->p; } return pt; }
【练习】
12.2-1 假设在某二叉查找树中,有1到1000之间的一些数,现要找出363这个数。下列的结点序列中,哪一个不可能是所检查的序列。
b) c) e) 不是
12.2-2 写出TREE-MINIMUM和TREE-MAXIMUM过程的递归版本。
NODE* getMinimum(NODE *rt) { if (rt->l!=NULL) return getMinimum(rt->l); return rt; }
12.2-3 写出TREE-PREDECESSOR过程。
NODE* treePredecessor(NODE *rt) { if (rt->l!=NULL) return treeMaximum(rt->l); NODE* pt=rt->p; while (pt!=NULL && rt==pt->l) { rt=pt; pt=pt->p; } return pt; }
12.2-4 假设对关键字k的查找在一个叶节点处结束,考虑三个集合,A,包含查找路径左边的关键字;B,包含查找路径上的关键字;C,包含查找路径右边的关键字。给出a∈A,b∈B,c∈C,必定满足a<=b<=c的一个最小反例。
如图 20∈A,10∈B,20>10。
12.2-5 证明:如果二叉查找树中的某个结点有两个子女,则其后继没有左子女,其前驱没有右子女。
若该结点有左子女,则其前驱为左子树中的最大值即左子树的最左,显然没有左子女。
若该节点有右子女,则其后继为右子树中的最大值即右子树的最右,显然没有右子女。
12.2-6 考虑一棵其关键字各不相同的二叉查找树T。证明:如果T中某个结点x的右子树为空,且x有一个后继y,那么y就是x的最低祖先,且其他左孩子也是x的祖先。
考虑二叉查找树的中序遍历,对一个结点k,left[k]为根的子树中最大元素的后继是k,k的后继在right[k]中,right[k]为根的子树中最大元素的后继即为left[p[k]]或right[p[k]]的后继问题。由此可知,x的第一个右祖先y就是x的后继,y的左儿子和左儿子的左儿子等等都是x的祖先。
12.2-7 对于一棵包含n个结点的二叉查找树,其中序遍历可以这样来实现:先用TREE-MINIMUM找出树中的最小元素,然后再调用n-1次TREE-SUCCESSOR。证明这个算法的运行时间为Θ(n)。
TREE-MINIMUM运行时间为O(h)。n-1次TREE-SUCCESSOR实质上是非递归不用栈实现中序遍历的过程,因此运行时间为Θ(n)。
12.2-8 证明:在一棵高度为h的二叉查找树中,无论从哪一个结点开始,连续使用k次调用TREE-SUCCESSOR所需的时间是O(k+h)。
每个结点最多访问三次?
12.2-9 设T为一棵其关键字均不相同的二叉查找树,并设x为一个叶子结点,y为其父结点。证明:key[y]或者是T中大于key[x]的最小关键字,或者是T中小于key[x]的最大关键字。
若x为y的左孩子,查找y的前驱,显然最左孩子为x。因此key[y]为大于key[x]的最小关键字。
若x为y的右孩子,查找y的后继,显然最右孩子为x。因此key[y]为小于key[x]的最大关键字。