搜索對象是一個數據的集合(稱為搜索表),除了執行搜索外,還可能執行其他操作,例如添加新元素,這樣可能會改變搜索表的結構。因此,搜索表可以區分為靜態搜索表(表的結構不發生改變)和動態搜索表兩種情況。
常見的適用於靜態搜索表的搜索方法有:順序搜索、折半搜索、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++描述) 清華大學出版社 石志國
