zoukankan      html  css  js  c++  java
  • 算法导论读书笔记(12)

    算法导论读书笔记(12)

    二叉查找树

    如下图所示,一棵二叉查找树是按二叉树结构来组织的。这样的树可以用链表结构来表示,其中每一个结点都是一个对象。结点中除了 key 域和卫星数据外,还包含域 leftrightp ,它们分别指向结点的左儿子,右儿子和父结点。如果某个儿子结点或父结点不存在,则相应域中的值为 NIL 。根结点是树中唯一的父结点为 NIL 的结点。

    在二叉查找树(binary search tree)上执行的基本操作的时间与树的高度成正比。对于一棵含 n 个结点的完全二叉树,这些操作的最坏情况运行时间为 Θ ( lg n )。但是,如果树是含 n 个结点的线性链,则这些操作的最坏情况运行时间为 Θ ( n )。

    二叉查找树中关键字的存储方式总是满足以下的 二叉查找树 性质:

    x 为二叉查找树中的一个结点。如果 yx 的左子树中的一个结点,则 y.key <= x.key 。如果 yx 的右子树中的一个结点,则 y.key >= x.key

    根据二叉查找树的性质,可以用一个递归算法按排列顺序输出树中的所有关键字。这种算法称为 中序遍历算法 ,因为子树根的关键字在输出时介于左子树和右子树的关键字之间(类似地, 前序遍历 中根的关键字在其左右子树的关键字之前输出,而 后序遍历 中根的关键字在其左右子树的关键字之后输出)。

    INORDER-TREE-WALK(x)
    1 if x != NIL
    2     INORDER-TREE-WALK(x.left)
    3     print x.key
    4     INORDER-TREE-WALK(x.right)
    

    定理
    如果 x 是一棵包含 n 个结点的子树的根,则调用 INORDER-TREE-WALK(x) 过程的时间为 Θ ( n )。

    查询二叉查找树

    对于二叉查找树,最常见的查找操作除了 SEARCH 外,二叉查找树还支持 MINIMUMMAXIMUMSUCCESSORPREDECESSOR 等查询。对高度为 h 的树,它们都可以在 O ( h )时间内完成。

    查找

    下面的过程在树中查找一个给定的关键字。

    TREE-SEARCH(x, k)
    1 if x == NIL or k == x.key
    2     return x
    3 if k < x.key
    4     return TREE-SEARCH(x.left, k)
    5 else
    6     return TREE-SEARCH(x.right, k)
    

    该过程从树的根结点开始进行查找,并沿树下降。对碰到的每个结点 x ,就比较 kx.key 。如果这两个关键字相同,则查找结束。如果 k 小于 x.key ,则继续查找 x 的左子树,如果 k 大于 x.key ,则继续在 x 的右子树中查找。也可以用 while 循环来替代递归过程。

    ITERATIVE-TREE-SEARCH(x, k)
    1 while x != NIL and k != x.key
    2     if k < x.key
    3         x = x.left
    4     else
    5         x = x.right
    6 return x
    

    最大关键字元素和最小关键字元素

    要查找二叉树中具有最小关键字的元素,只要从根结点开始,沿着各结点的 left 指针查找下去,直到遇到 NIL 时为止。

    TREE-MINIMUM(x)
    1 while x.left != NIL
    2     x = x.left
    3 return x
    

    在以 x 为根的子树中,最小关键字可以在 x.left 为根的左子树中找到。过程 TREE-MAXIMUM 的伪码是对称的:

    TREE-MAXIMUM(x)
    1 while x.right != NIL
    2     x = x.right
    3 return x
    

    对高度为 h 的树,这两个过程的运行时间都是 O ( h )。

    前趋和后继

    给定一个二叉查找树中的结点,有时要求找出其在中序遍历顺序下它的后继。如果所有的关键字均不相同,则某一结点 x 的后继即具有大于 x.key 中的关键字中最小者的那个结点。

    TREE-SUCCESSOR(x)
    1 if x.right != NIL
    2     return TREE-MINIMUM(x.right)
    3 y = x.p
    4 while y != NIL and x == y.right
    5     x = y
    6     y = y.p
    7 return y
    

    TREE-SUCCESSOR 代码中包含两种情况。

    • 如果结点 x 的右子树非空,则 x 的后继即右子树中的最左结点,可以通过 TREE-MINIMUM(x.right) 过程找到。
    • 如果结点 x 的右子树为空,且 x 有一个后继 y ,则 yx 的最低祖先结点,且 y 的左儿子也是 x 的祖先。

    如下图所示,包含关键字15的结点的后继是包含关键字17的结点。包含关键字13的结点的后继是包含关键字15的结点。

    过程 TREE-PREDECESSORTREE-SUCCESSOR 对称,其运行时间都是 O ( h )。

    TREE-PREDECESSOR(x)
    1 if x.left != NIL
    2     return TREE-MAXIMUM(x.left)
    3 y = x.p
    4 while y != NIL and x == y.left
    5     x = y
    6     y = y.p
    7 return y
    

    插入和删除

    插入和删除操作会引起二叉树结构上的变化,这时,就要修改其数据结构,以保持二叉查找树性质。

    插入

    为将一个新值 v 插入到二叉查找树 T 中,可以调用 TREE-INSERT 。传给该过程的参数是个结点 z ,并且有 z.key = vz.left = NILz.right = NIL

    TREE-INSERT(T, z)
    1  y = NIL
    2  x = T.root
    3  while x != NIL
    4      y = x
    5      if z.key < x.key
    6          x = x.left
    7      else
    8          x = x.right
    9  z.p = y
    10 if y == NIL
    11     T.root = z    // tree T was empty
    12 elseif z.key < y.key
    13     y.left = z
    14 else
    15     y.right = z
    

    TREE-INSERT 过程从根结点开始,并沿树下降。指针 x 跟踪了这条路径,而 y 始终指向 x 的父结点。过程根据 z.keyx.key 的比较结果,决定向左或向右转。这到 x 成为 NIL 为止。这个 NIL 所占位置即我们想插入项 z 的地方。

    删除

    将结点 z 从二叉查找树 T 中删除共有如下三种情况,其中一种有一点难懂。

    • 如果结点 z 没有孩子结点,我们就可以直接使用 NIL 来代替该结点。
    • 如果结点 z 只有一个子女,可以直接用结点 z 的孩子结点替代 z
    • 如果结点 z 有两个子女,首先要找到结点 z 的后继 y (它一定在 z 的右子树中),并用 y 替代 z 在树中的位置。

    TREE-DELETE 过程用于从二叉查找树 T 中删除一个给定的结点 z ,它按如下四种情况组织代码。

    • 如果结点 z 没有左孩子,那么我们用右孩子替换 z ,其中右孩子可能为 NIL 。右孩子为 NIL 即结点 z 没有孩子结点的情况。
    • 如果结点 z 有且只有左孩子,那么就用左孩子替代结点 z
    • 否则,结点 z 有两个子结点。首先找到 z 的后继结点 y ,它位于 z 的右子树且没有左孩子。这里我们打算用 y 替换 z
      • 如果 yz 的右孩子,那么直接用 y 替换 z
      • 否则,用 y 自己的右孩子替换 y ,再用 y 来替换 z

    此外还有一个子程序 TRANSPLANT ,用于子树之间的替换。

    TRANSPLANT(T, u, v)
    1 if u.p == NIL
    2     T.root = v
    3 elseif u == u.p.left
    4     u.p.left = v
    5 else
    6     u.p.right = v
    7 if v != NIL
    8     v.p = u.p
    
    TREE-DELETE(T, z)
    1  if z.left == NIL
    2      TRANSPLANT(T, z, z.right)
    3  elseif z.right == NIL
    4      TRANSPLANT(T, z, z.left)
    5  else
    6      y = TREE-MINIMUM(z.right)
    7      if y.p != z
    8          TRANSPLANT(T, y, y.right)
    9          y.right = z.right
    10         y.right.p = y
    11     TRANSPLANT(T, z, y)
    12     y.left = z.left
    13     y.left.p = y
    
  • 相关阅读:
    HDU 1525
    kmp模板
    hdu 4616 Game(树形DP)
    hdu 4619 Warm up 2(并查集活用)
    hdu 4614 Vases and Flowers(线段树加二分查找)
    Codeforces 400D Dima and Bacteria(并查集最短路)
    poj 2823 Sliding Window (单调队列)
    hdu 2196 Computer(树形dp)
    hdu 4604 Deque
    最短路径
  • 原文地址:https://www.cnblogs.com/sungoshawk/p/3722604.html
Copyright © 2011-2022 走看看