zoukankan      html  css  js  c++  java
  • 算法导论第十二章:二叉查找树

    查找树是一种数据结构,它支持多种动态集合操作,包括search, minimum, maximum, predecessor, successor, insert以及delete。他既可以用作字典,也可以用作优先队列。

    二叉查找树上基本操作的执行时间和树的高度成正比。对一棵n个结点的完全二叉树来说,这些操作的最坏情况运行时间为Θ(lgn)。但是如果树是含有那个结点的线性链,则这些操作的最坏运行时间是Θ(n)。本章可以看到一棵随机构造的二叉查找树的期望高度为O(lgn)

    实际中,并不能总是保证二叉查找树是随机构造的,但有些二叉查找树的变形能保证各种基本操作的最坏情况性能。第十三章介绍的红黑树,其高度为O(lgn)。第十八章介绍B树,这种结构对维护随机访问的二级存储器上的数据库特别有效。

     

    二叉查找树

      二叉查找树是按二叉树结构来组织的,每个结点除了key域和卫星数据外,还包含leftrightp。结点的存储方案满足以下性质:如果结点y是结点x左子树种的一个结点,则key[y]<=key[x]。如果yx右子树中的一个结点,则key[x]<=key[y]

     

    对二叉查找树进行中序遍历可以有序输出所有的结点关键字。

     

    练习:

    12.1.3给出二叉树的一个非递归的中序遍历算法。

    1)可以用一个栈数据结构来模拟递归过程中的栈变化过程,从而完成非递归形式的遍历算法;

    2)也可以不借助栈数据结构,中序遍历的过程中是由从根到叶、从父到子的down过和从子到父的up过程组成的。在非递归的情况下,在处理某个节点x时,关键是要分清下一步是要down还是up。其实这可以由上一个结点位置来判断,如果上一个结点是x的父节点且x是它的左儿子,则应该往左down,如果x是它的右儿子,则应该up。如果上一结点是x的左儿子,则应该往右down,如果是x的右儿子,则应该up

    OPTYPE {down, up}

    INORDER_WITHOUTSTACKT

    1         Node x = root[T]

    2         Node last_node = nil

    3         OPTYPE last_op = down

    4         while (!over)

    5           switch (last_op)

    6             Case down:       

    7                If (left[x]) last_node=x, last_op=down, x=left[x]

    8                Else output(x);

    9                    if (right[x]) last_node=x, last_op=down, x=right[x]

    10                Else if (x.p) last_node=x,last_op=up,x=x.p

    11                    Else over=true

    12         Case up:

    13            If (last_node = left[x]) output(x)

    14                               If (right[x]) last_node=x, last_op=down, x=right[x]

    15                             Else if (x.p) last_node=x,last_op=up,x=x.p

    16                                 Else over=true

    17          Else if (x.p) last_node=x,last_op=up,x=x.p

    18                                 Else over=true 

     

    查询二叉查找树

    查找关键字k

    从树根开始比较key[x]k,如果key[x]=k停止,如果key[x]>k则往左子树查找,否则往右子树查找,如此循环。

     

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

    最大关键字就是树的最右结点:沿树根往右子节点移动,直到NIL

    最小关键字元素就是树的最左结点:沿树根往左子结点移动,直到NIL

     

    前驱和后继:

    某个节点x的前驱:如果x有左子,那么前驱是左子树的最大关键字;否则从下往上查看x的祖先结点,直到某个节点y满足性质:x出现在y的右子树种。如果y存在,则y就是x的前驱,否则x没有前驱。

    某个节点x的后继:如果x有右子,则x的后继是右子树的最小关键字;否则从下往上查看x的祖先结点,直到某个结点y满足性质:x出现在y的左字数中,如果y存在,则yx的后继,否则x没有后继。

     

    查找前驱和后继的最坏运行时间为lgn

    但对x查找其后继(前驱)的k个结点的运行时间为lgn+k,以前驱为例,证明如下:

    假设x的左子树有k1个结点,如果k<k1,则k1时间内就可以完成,假设k1<k,遍历这k1个结点需要k1时间,找到下一个前驱需要往根方向移动,不妨设移动的距离为h1。如此往复。假设期间产生了 k1,k2,k3..h1,h2…这些数据。可知 k1+k2+k3…<=kh1+h2+…<=树的高度。所以运行时间k1+k2+k3+…+h1+h2+…<=lgn+k

    实际上,如果对树的最小结点调用n-1次后继操作,等同于中序遍历二叉查找树。

     

    插入删除结点

    插入一个结点与查找一个关键字的过程是基本一致的。当查找过程到达nil时,这个位置就是插入的位置。

    删除的过程要稍微复杂一点:

    (1)       如果结点没有子节点,则直接删除。

    (2)       如果结点只有左子树或右子树,则删除该节点,然后用该子树的根节点来取代该节点的位置。

    (3)       如果该节点有左右子树,则将该节点的数据与其前驱或后继结点的数据进行交换,再删除该前驱或后继结点

     

    随机构造的二叉查找树

    二叉查找树的操作性能依赖于树的高度,为了避免坏的关键字顺序造成树的高度过高,可以采用随机化的手段来构造树。可以证明,随机构造的二叉查找树的期望高度为O(lgn)

    先定义三个随机变量:

    Xnn个结点的二叉查找树的高度;

    Yn:指数高度Yn=2XnYn = 2*max(Yi-1,Yn-i)

    Rn:根节点的在关键字中的统计顺序。

    Zn,i:定义指示器随机变量Zn,i=I{Rn=i}; E[Zn,i] = 1/n

    推理过程如下:

                                                                        

    利用恒等式:,用数学归纳得出,再利用jensen不等式:,可得E[Xn] = O(lgn)

     

    随机构造二叉查找树与随机化快速排序比较

    在构造二叉树的时候,当选定某个关键字称为根节点之后,那么比这个关键字大的关键字都将出现在该节点的右字数,小的关键字都将出现在左子树。这个过程与快速排序选定中轴节点的过程及其相似。进一步,所有的结点都将与根节点进行比较,但左子树中的结点不会与右子树的结点比较,反之亦然。可以看出构造二叉查找树的过程与快速排序的过程惊人地相似,实际上如果将选定根节点和选定中轴结点相对应,那么两者整个过程中所进行的元素比较是完全相同的,只是顺序不一致而已。

     

    可以分析二叉查找树的平均结点深度。每个结点的深度等于其在插入树的过程中的比较次数,所有的比较次数之和平均为nlgn,因此平均的结点深度为lgn

     

    思考题

    基数树:

    基数树数据结构,用来存储0,1位串,位置串并没有存储在节点中,一个结点只要标明从根到该节点的路径是否构成一个有效位串。当查找某关键字a=a0a1…ap,时,在深度为i的一个结点处,如果ai=0,则向左转,如果ai=1则向右转。下图的基数树存储了位串0,001,10 1001011.白色结点为有效位串的终结结点。

    S为一组不同的二进制构成的集合,各串的长度之和为n。说明如何利用基数树,在Θ(n)时间内将S按字典顺序排序。

     

    分析:构造基数树的过程很显然,假设一个位串的长度为k,则只需要时间k就可以将串插入基数树中。然后进行中序遍历就可以,按序输出。

    如果将基数树扩展,是否可以用来存储一般的字符串,并加快查找过程?

     

  • 相关阅读:
    Android -- 自定义View小Demo,动态画圆(一)
    Android -- 自定义View小Demo,绘制四位数随机码(一)
    Android设计模式---观察者模式小demo(一)
    Android -- 自定义View小Demo,绘制钟表时间(一)
    Android -- 自定义View小Demo,关于Rect绘制Android机器人(一)
    Android -- 自定义View小Demo,关于Path类的使用(一)
    Android -- 自定义View小Demo(一)
    Android -- 自定义View(一)
    自定义Scrollview--实现仿淘宝Toolbar透明度渐变效果
    究竟什么是技术——非科班程序员两年的内心挣扎
  • 原文地址:https://www.cnblogs.com/longhuihu/p/10423370.html
Copyright © 2011-2022 走看看