算法导论第十二章总结以及课后题答案

二叉搜索树

总结

1.查找二叉搜索树中最大关键字元素
TREE-MAXIMUM(x)
  while x.right!=NIL
    x=x.right
  return x
2.查找二叉搜索树中最小关键字元素
TREE-MINIMUM(x)
  while x.left!=NIL
    x=x.left
  return x
3.插入一个结点到二叉树
TREE-INSERT(T,z)
  y=NIL  //y结点的作用是保存找到的z的双亲结点
  x=T.root  //从根结点开始向下寻找
  while x!=NIL
    y=x
    if z.key
4.二叉搜索树后继结点的查找
算法导论第十二章总结以及课后题答案_第1张图片
一个结点的后继是大于x.key的最小关键字的结点(结点3的后继为8)
TREE-SUCCESSOR(x)
  if x.right!=NIL  //如果结点x的右子树不为空,那么x的后继就是x右子树中的最左结点
    return TREE-MINIMUM(X.right)
  else  //如果x的右子树为空,为了找到后继结点y,需要从x开始沿树而上遇到这样一个结点:这个结点是它双亲的左孩子
    y=x.p
    while y!=NIL and x==y.right
      x=y
      y=y.p
    return y
5.删除二叉搜索树中的一个结点
子过程TRANSPLANT是用另一颗子树替换一颗子树并成为其双亲的孩子结点
TRANSPLANT(T,u,v)
  if u.p==NIL  //u是树根,则替换后v就是树根
    T.root=v
  else if u=u.p.left
    u.p.left=v  //如果u是双亲的左孩子,则v代替u成为u双亲的左孩子
  else
    u.p.right=v  //如果u是双亲的右孩子,则v代替u成为u双亲的右孩子
  if v!=NIL  //v其实可以为空
    v.p=u.p
注意:上述TRANSPLANT没有处理v.left和v.right的更新,这也就是说,用子树v替换完u之后,v.left和v.right的更新要由TRANSPLANT的调用者负责。

TREE-DELETE(T,z)
  if z.left==NIL  //结点z没有左孩子,则直接用结点z的右孩子这棵子树对z这棵子树进行替换
    TRANSPLANT(T,z,z.right)
  else if z.right==NIL  //结点z没有左孩子,则直接用结点z的右孩子这棵子树对z这棵子树进行替换
    TRANSPLANT(T,z,z.left)
  else y=TREE-MINIMUM(z.right)  //结点的左右孩子均存在,通过调用TREE-MINIMUM(查找比给定结点大的最小结点也就是后继结点)查找结点z的后继y,用它来替代z  
    if y.p!=z  //如果找到的y不是z的孩子结点,则y结点必然没有左孩子(否则y就不是z的后继结点)。
      TRANSPLANT(T,y,y.right)  //先用y的右孩子这棵子树替代y子树
      y.right=z.right  //此时,将z的右孩子赋予y的右孩子
      y.right.p=y   
    TRANSPLANT(T,z,y)  //如果找到的y是z的孩子结点,则子树y对子树z进行替换。否则,用更新后的子树y对子树z进行替换
    y.left=z.left  //y的孩子的更新
    y.left.p=y


课后题答案

12.1-2 二叉搜索树性质与最小堆性质之间有什么不同?

1.二叉排序树是为了实现动态查找而设计的数据结构,它是面向查找操作的,在二叉排序树中查找一个结点的平均时间复杂度是O(log n);
堆是为了实现排序而设计的一种数据结构,它不是面向查找操作的,因而在堆中查找一个结点需要进行遍历,其平均时间复杂度是O(n)

2.在二叉排序树中,某结点的右孩子结点的值一定大于该结点的左孩子结点的值;

在堆中却不一定,堆只是限定了某结点的值大于(或小于)其左右孩子结点的值,但没有限定左右孩子结点之间的大小关系。

3.具有n个结点的二叉排序树,其深度取决于给定集合的初始排列顺序,最好情况下其深度为lgn,最坏情况下其深度为n;

具有n个结点的堆,其深度为lgn 。

12.1-3 设计一个执行中序遍历的非递归算法。
INORDER-TREE-WALK(x)
  node=root
  while node!=NIL || !stack.empty()
    if node!=NIL
      push(node)
      node=node.left  //从根结点开始,先将左孩子入栈
    else  
      node=top()  //左孩子为空时,对栈顶元素进行出栈
      visit(node)  //读取node的关键字
      node=node.right  //转到出栈元素的右孩子


12.2-3 写出过程TREE-PREDECESSOR的伪代码。

TREE-PREDECESSOR(x)
  if x.left!=NIL  //如果结点x的左子树不为空,那么x的后继就是x左子树中的最右结点
    return TREE-MAXIMUM(x.left)
  else  //如果x的左子树为空,为了找到前驱结点y,需要从x开始沿树而上遇到这样一个结点:这个结点是它双亲的右孩子
    y=x.p
    while y!=NIL and x==y.left
      x=y
      y=y.p
    return y

12.3-1 给出TREE-INSERT过程的一个递归版本。

RECURSIVE-INSERT(x,z)  //以x结点为树根的树中插入结点z
  if z.keyx.key and x.right!=NIL
    RECURSIVE-INSERT(x.right,z)
  z.parent=x
  if z.key



你可能感兴趣的:(算法,二叉搜索树,数据结构,答案)