查找二 树与图的搜索

搜索对象是一个数据的集合(称为搜索表),除了执行搜索外,还可能执行其他操作,例如添加新元素,这样可能会改变搜索表的结构。因此,搜索表可以区分为静态搜索表(表的结构不发生改变)和动态搜索表两种情况。

常见的适用于静态搜索表的搜索方法有:顺序搜索、折半搜索、Fibonacci搜索等。

适用于动态搜索表的搜索方法有:二叉排序算法,平衡二叉搜索算法。

二叉排序树搜索

二叉排序树(Binary sort Tree,BST)又称为二叉查找(搜索)树(Binary Search Tree) 。其必须为二叉排序树或者为空树,或者满足如下性质的二叉树:

(1)若它的左子树非空,则左子树所有结点的值均小于根结点的值;

(2)若它的右子树非空,则右子树上所有结点的值均大于根结点的值;

(3)左、右子树本身又各是一颗二叉排序树。

由BST性质可得:

1)二叉排序树中任一结点x,其左(右)子树中任一结点y(若存在)的关键字必小(大)于x的关键字。

2)二叉排序树,各结点关键字是唯一的。

实际运用中,不能保证被查找的数据集中各元素的关键字互不相同,所以可将二叉排序树定义中BST性质(1)里的“小于”改为“大于等于”,或将BST性质(2)里的“大于”改为“小于等于”,甚至可同时修改这两个性质。

3)按中序遍历该树所得到的中序序列是一个递增有序序列。

二叉排序树的存储结构表示如下:

typedef int KeyType;//假定关键字类型为整数
typedef struct node {//结点类型
    KeyType key;//关键字项
    InfoType otherinfo;//其他数据域,InfoType视应用情况而定,下面不处理它
    struct node *lchild,*rchild;//左右孩子指针
} BSTNode;
typedef BSTNode *BSTree;//BSTree是二叉排序树的类型

  

B-树

当查找文件较大,且存放在磁盘等直接存取设备中时,为了减少查找过程中对磁盘的读写次数,提高查找效率,基于直接存取设备的读写操作以“页”为单位的特征。1972年提出了一种称之为B-树的多路平衡查找树。它适合在磁盘等直接存取设备上组织动态的查找表。一颗m(m>=3)阶的B-树是满足如下性质的m叉树:

(1)每个节点至少包含下列数据域:(j,P0,K1,P1,k2,……,Ki,Pi)。其中:

j为关键字总数,

Ki(1<=i<=j)是关键字,关键字序列递增有序:K1<K2<……<Ki。

Pi(0<=i<=j)是孩子指针。对于叶节点,每个Pi为空指针。

注意:

实际运用中没结束空间,叶节点可省去指针域Pi,但必须在每个结点中增加一个标志域leaf,其值为真时表示叶节点,否则为内部结点。

在每个内部结点中,假设用keys(Pi)来表示子树Pi中的所有关键字,则有keys(P0)<K1<keys(P1)<K2<……<Ki<keys(Pi),即关键字是分界点,任一关键字Ki左边子树中的所有关键字均小于Ki,右边子树中的所有关键字均大于Ki。

(2)所有叶子是在同一层,叶子层数位树的高度h。

(3)每个非根结点中所包含的关键字个数j满足:m/2-1<=j<=m-1,m为阶数。

即每个非根结点至少应该有m/2-1个关键字,至多有m-1个关键字。因为每个内部结点的个数正好是关键字总数加1,故每个非根的内部结点至少有m/2棵子树,至多有m棵子树。

(4)若树非空,则根至少有1个关键字,故若根不是叶子,则它至少有2棵子树。根至多有m-1个关键字,故至多有m棵子树。

B-树的结点规模

B-树的算法执行时间主要是由读写磁盘的次数来决定的,每次读写尽可能多的信息可提高算法的执行速度。

B-树的结点规模一般是一个磁盘页,而结点中的所包含的关键字及其孩子的数目取决于磁盘页的大小。

注意:

1)对于磁盘上一颗较大B-树,通常每个结点拥有的孩子数目(即结点的度数)m为50至2000不等。

2)一颗度为m的B-树称为m阶B-树。

3)选取较大的结点度数可降低树的高度,以及减少查找任意关键字所需的磁盘访问次数。

B-树的存储结构

#define Max 1000    //结点中关键字的最大数目:Max=m-1,m是B-树的阶
#define Min 500        // 非根结点中关键字的最小数目:Min=m/2-1   
typedef int KeyType;//KeyType应由用户定义
typedef struct node {//结点定义中省略了指向关键字代表的记录的指针
    int keynum;//结点中当前拥有的关键字的个数,keynum<<Max
    KeyType key[Max+1];//关键字向量为key[1……keynum],key[0]不用
    struct node *parent;    //指向双亲结点
    struct node *son[Max+1];//孩子指针向量为son[0……keynum]
 }BTreeNode;
typedef BTreeNode *BTree;

  

广度优先搜索

搜索图常用方法有深度优先搜索和广度优先搜索两种。它们对无向图和有向图都适用。

广度优先搜索(BFS)类似于树按层次遍历的过程。广泛应用于求解问题的最短路径、最少步骤、最优方法等方面。

广度优先搜索遍历图的过程中以V为起始点,由近及远,依次访问和V右路径相通且路径长度为1,2……的顶点。

BFS(图g,顶点s)
{
    队列Q;
    for(顶点u in g.所有顶点)    u.状态=未访问;
    s.状态=准备访问;
    s.访问深度=0;
    Q.入队(s);
    while( Q.非空() )
    {
     顶点u=Q.出队();
     for(顶点v in u.所有邻接点)
     {
      if(v.状态==未访问)
      {
        v.状态=准备访问;
        v.访问深度=v.访问深度+1;
        v.前趋点=u;
        Q.入队(v);    
       }
     }
    u.状态=已访问;
   }
}
            
    

  

深度优先搜索

DFS类似于树的先根遍历,是树的先根遍历的推广。常用于游戏软件开发中。深度优先搜索的核心思想是在搜索到尽头时,用栈记住下一步的走向。

DFS(图g,顶点s)
{
  s.状态=正在访问;
  
  for(顶点v in s.所有邻接点)
  {
   if(s.状态 == 未访问)
       DFS(g,v);
   }

  s.状态=已访问;  
}

  在遍历图的时候,对图中每个顶点至多调用一次深度优先搜索,遍历图的过程实质上是对每个顶点查找其邻接点的过程,其耗费的时间取决于所采用的数据结构。当用邻接矩阵存储图时,查找一个顶点的邻接点所需时间为O(n)(n表示图中顶点数目),则总的时间复杂度为T(n)=O(n^2).

---------------------------------------------------------------------------------

参考文献《算法分析与设计》 (C++描述)   清华大学出版社 石志国

拥抱明天! 不给自己做枷锁去限制自己。 别让时代的悲哀,成为你人生的悲哀。
原文地址:https://www.cnblogs.com/dd2hm/p/7221620.html