查找二 樹與圖的搜索


搜索對象是一個數據的集合(稱為搜索表),除了執行搜索外,還可能執行其他操作,例如添加新元素,這樣可能會改變搜索表的結構。因此,搜索表可以區分為靜態搜索表(表的結構不發生改變)和動態搜索表兩種情況。

常見的適用於靜態搜索表的搜索方法有:順序搜索、折半搜索、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++描述)   清華大學出版社 石志國

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM