1. 程式人生 > 實用技巧 >9.0 查詢

9.0 查詢

title: 資料結構 | 查詢
date: 2019-12-8 11:39:58

tags: 資料結構

靜態查詢表:順序查詢和折半查詢;
動態查詢表:二叉排序樹、二叉平衡樹、B/B+樹、雜湊查詢、雜湊表

主要內容

  • 9.1 靜態查詢表
    9.1.1 順序表的查詢
    9.1.2 有序表的查詢
  • 9.2 動態查詢表
    9.2.1 二叉排序樹和二叉平衡樹
    9.2.2 B_樹和B+樹//本篇文章此處截止
  • 9.3 雜湊( Hashing )表(散列表)

參考資料
B樹部分大面積整理使用了這位文哥的資料,前輩總結的真的特別好,這裡直接使用了……侵刪。
作者:文哥的學習日記
連結:https://www.jianshu.com/p/7dedb7ebe033

概 述

  • 查詢表 (search table):
    同一型別資料元素構成的集合。
  • 查詢操作:
    (1)查詢某個“特定的”資料元素是否在查詢表中;
    (2)檢索某個“特定的”資料元素的各種屬性;
    (3)在查詢表中插入一個數據元素;
    (4)從查詢表中刪除某個資料元素.
    靜態查詢表:對查詢表只作(1)、(2)操作;
    動態查詢表:可以對查詢表作(1)-(4)操作。
  • 查詢方法評價
    1.查詢速度
    2.佔用儲存空間多少
    3.演算法本身複雜程度
    4.平均查詢長度ASL(Average Search Length):為確定記錄在表中的位置,需和給定值進行比較的關鍵字的個數的期望值叫查詢演算法的ASL。

靜態查詢表

定義

只提供如下兩種查詢的查詢表:
1) 查詢某個“特定”元素是否在表中;
2) 檢索某個“特定”元素的各種屬性;

順序表及其查詢 —— 順序查詢法

查詢表組織

查詢表用線性表表示。
即將查詢表的記錄排成一個記錄序列(無序)。
L1=(45,53,12,3,37,24,100,61,90,78)

typedef struct{ //靜態查詢表的順序儲存結構
   ElemType *elem;
   int length;
}SSTable;

順序查詢

查詢過程:從表的一端開始逐個進行記錄的關鍵字和給定值的比較

逐一比較,且設定0號位置為監視哨,0處值等於待查詢值。

順序查詢的效能分析

平均查詢長度ASLss=(n+1)/2

順序查詢的演算法

int Search_Seq(SSTable ST, KeyType key){
   //在順序表ST中順序查詢其關鍵字等於key的資料元素。
   //若找到,則函式值為該元素在表中的位置,否則為0。
    ST.elem[0].key=key;   // “哨兵”
    for(i=ST.length;!EQ(key,ST.elem[mid].key);--i) 
      //從後向前找
    return i;     //若表中不存在待查元素,i=0
    }//Search_Seq

有序表及其查詢 —— 折半查詢法

  • 有序表
    若線性表中的記錄按關鍵字有序,則稱為有序表

查詢表組織

查詢表用有序表表示。
即將查詢表的記錄排成按關鍵字有序的序列。

折半查詢

  • 查詢過程:每次將待查記錄所在區間縮小一半
  • 適用條件:採用順序儲存結構的有序表
  • 演算法實現
    設表長為n,low、high和mid分別指向待查元素所在區間的上界、下界和中點,k為給定值
    初始時,令low=1,high=n,mid=floor[(low+high)/2]
    讓k與mid指向的記錄比較:
    若k==r[mid].key,查詢成功;
    若k<r[mid].key,則high=mid-1;
    若k>r[mid].key,則low=mid+1;
    重複上述操作,直至low>high時,查詢失敗.

折半查詢的效能分析

查詢過程中所有元素可構成一顆判定二叉樹,例如:

  • 判定樹上每個結點需要的查詢次數剛好為該結點所在的層數.
  • 無論查詢成功或失敗,次數不會超過判定樹的深度
  • n個結點的判定樹的深度為[log2n]+1
  • 折半查詢的演算法複雜度不超過[log2n]+1

查詢成功時的平均查詢長度
ASLbs= log2(n+1)-1

折半查詢的演算法

int Search_Bin ( SSTable ST, KeyType key ) { 
// 在有序表ST中折半查詢其關鍵字等於key的資料元素。
// 若找到,則函式值為該元素在表中的位置,否則為0。
	low=1;high=ST.length; // 置區間初值
		while (low<=high) {
			mid=(low+high)/2;
		if(EQ(key,ST.elem[mid].key))
			return mid; // 找到待查元素
		else if (LT(key,ST.elem[mid].key))
			high = mid - 1; // 繼續在前半區間進行查詢
		else
			low = mid + 1; // 繼續在後半區間進行查詢
		}
	return 0; // 順序表中不存在待查元素
} // Search_Bin

分塊查詢 —— 索引順序查詢

查詢表組織

分塊有序表

索引順序查詢

查詢過程
將表分成幾塊,塊內無序,塊間有序;
先確定待查記錄所在塊,再在塊內查詢。

索引順序查詢的效能分析

索引順序查詢的演算法實現

該表的構造過程是:把要查詢的表分成長度相等的幾個子表(稱為塊)。對每個子表建立一個索引項。
索引表中關鍵字遞增有序,具體表塊內部記錄可以無序。但塊之間一定有序(即後一塊中的最小關鍵字都大於前一塊中最大關鍵字)。
查詢過程分兩步:
1.首先在索引表中確定待查記錄所在的塊;
2.在塊中按順序查詢。
注意,索引表有序且是順序儲存結構中可以用折半查詢。塊中記錄無序只能用順序查詢。

查詢方法比較

順序查詢 折半查詢 分塊查詢
ASL 最大 最小 中間
表結構 有序/無序 有序 分塊有序
儲存結構 順序儲存結構/線性連結串列 順序儲存 順序儲存結構/線性連結串列

動態查詢表

定義

靜態以外,額外提供查詢後的插入和刪除操作。

二叉排序樹

定義

  • 二叉排序樹或是一棵空樹,或是具有下列性質的二叉樹:
    1.若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值
    2.若它的右子樹不空,則右子樹上所有結點的值均大於或等於它的根結點的值
    3.它的左、右子樹也分別為二叉排序樹

二叉排序樹的插入(生成)

  • 插入原則
    若二叉排序樹為空,則插入結點應為新的根結點;否則,繼續在其左、右子樹上查詢,直至某個葉子結點的左子樹或右子樹為空為止,則插入結點應為該葉子結點的左孩子或右孩子
  • 二叉排序樹生成
    從空樹出發,經過一系列的查詢、插入操作之後,可生成一棵二叉排序樹

查詢演算法一

//在根指標T所指二叉排序樹中遞迴地查詢某關鍵字等於key的資料元素,
//若查詢成功,則返回指向該資料元素結點的指標,否則返回空指標。
BiTree SearchBST(BiTree T,KeyType key){
   if(!T)||EQ(key,T->data.key)) 
      return(T);
   else if LT(key, T->data.key) //查詢的值比當前節點小
      return(SearchBST(T->lchild,key));
   else
      return(SearchBST(T->rchild.key));
}//SearchBST

查詢演算法二

//在根指標T所指二叉排序樹中遞迴地查詢其關鍵字等於key的資料元素,若查詢
//成功,則指標p指向該資料元素結點,並返回TRUE,否則指標p指向查詢路徑上
//訪問的最後一個結點並返回FALSE,指標f指向T的雙親,其初始呼叫值為NULL
Status SearchBST(BiTree T,KeyType key,BiTree f,BiTree &p){
	if(!T) 
		{p=f;return FALSE;}
	else if EQ(key,T->data.key)
		{ p=T;return TRUE;}
	else if LT(key,T->data.key)//每一步查詢記錄cur的雙親,即把T賦給下一個f
		SearchBST(T->lchild,key,T,p);
	else    
		SearchBST(T->rchild,key,T,p);
}//SearchBST

插入演算法

// 當二叉排序樹T中不存在關鍵字等於e.key的資料元素時,插入e並返回TRUE,
// 否則返回FALSE。
Status InsertBST(BiTree &T,ElemType e){
	if(!SearchBST(T, e.key, NULL, p){
		s=(BiTree)malloc(sizeof(BiTNode));
		s->data=e;
		s->lchild=s->rchild=NULL;
		if(!p) //指標p指向了查詢路徑上訪問的最後一個結點
			T=s;//這裡是判斷若整個二叉樹為空,則把s作為根節點
		else if(LT(e.key,p->data.key)
			p->lchild=s;
		else 
			p->rchild=s;
		return TRUE;
	}
	else  return FALSE;
}//InsertBST

二叉排序樹的生成


注意:若有重複元素,則不再插入。

二叉排序樹的刪除

要刪除二叉排序樹中的p結點,分三種情況:

  • (1) p為葉子結點,只需修改p雙親f的指標
    f->lchild=NULL f->rchild=NULL
  • (2) p只有左子樹或右子樹
    p只有左子樹,用p的左孩子代替p (1)(2)
    p只有右子樹,用p的右孩子代替p (3)(4)
  • (3) p左、右子樹均非空
    沿p左子樹的根C右子樹分支找到S,滿足S的右子樹為空,將S的左子樹成為S的雙親Q的右子樹,用S取代p (5)
    若C無右子樹,用C取代p (6)
    也即S替代要刪的店,S的左子樹替代S。


演算法在二叉排序樹中刪除一個節點的演算法

Status DeleteBST(BiTree &T,KeyType key){
	if(!T) 
		return FALSE;
	else{
		if EQ(key,T->data.key) 
			Delete(T);
		else if LT(key,T->data.key) 
			DeleteBST(T->lchild, key);
		else 
			DeleteBST(T->rchild, key);
		return TRUE;
	}
}
void Delete(BiTree &p){
	if(!p->rchild){q=p;p=p->lchild;free(q);}
	//用p的左孩子代替p
	else if(!p->lchild){q=p;p=p->rchild;free(q);}
	//用p的右孩子代替p
	else{
		q=p;s=p->lchild;
		while(s->rchild){q=s;s=s->rchild;} 
		//轉左,然後向右到盡頭
		p->data=s->data;          //s指向被刪結點的"前驅"
		if(q!=p)
			q->rchild=s->lchild; //重接*q的右子樹
		else q->lchild=s->lchild;        //重接*q的左子樹 
	}
}//delete

二叉排序樹效能分析

只有二叉排序樹為平衡樹時,其平均查詢時間為O(log n),
反之,可能退化直到順序查詢O(n)。

平衡二叉樹

定義

平衡二叉樹又稱AVL樹
它或者是一棵空樹,或者是具有下列性質的二叉樹:
它的左子樹和右子樹都是平衡二叉樹,且左子樹和右子樹的深度之差的絕對值不超過1

平衡因子

結點的平衡因子BF(Balance Factor)是左子樹的深度減去右子樹的深度,它只可能是 -1, 0, 1

二叉排序樹轉成平衡樹

失去平衡後進行調整的四種情況

單向右旋平衡處理 LL型

當在左子樹上插入左結點,使平衡因子由1增至2時
調整過程
將BA向右旋轉90度,把B的右孩子變為A的左孩子,A變為B的右孩子,B替代A的位置。

單向左旋平衡處理 RR型

當在右子樹上插入右結點,使平衡因子由-1增至-2時
調整過程
將BA向右旋轉90度,把B的右孩子變為A的左孩子,A變為B的右孩子,B替代A的位置。

雙向旋轉(先左後右)平衡處理 LR型

當在左子樹上插入右結點,使平衡因子由1增至2時
調整過程
1)將CB向左旋轉90度,把CL變為B的右子樹,把B變為C 的左孩子;
2)將BCA向右旋轉90 度,把CR變為A的左孩子,A變為C的右孩子;最後,C帶替A的位置。

雙向旋轉(先右後左)平衡處理 RL型

當在右子樹上插入左結點,使平衡因子由-1增至-2時
調整過程
1)將CB向右旋轉90度,把CR變為B的右子樹,把B變為C的左孩子;
2)將BCA向左旋轉90度,把C的左孩子變為A的右孩子,A變為C的左孩子;最後,C帶替A的位置。

平衡二叉樹的查詢及效能分析

它的時間複雜度與二叉排序樹的最好時間複雜相同,都為O(log2n)。

B-樹

類似“多叉的”二叉查詢樹

定義

B-樹中所有結點中孩子結點個數的最大值成為B-樹的階,通常用m表示,從查詢效率考慮,一般要求m>=3。一棵m階B-樹或者是一棵空樹,或者是滿足以下條件的m叉樹。
1)每個結點最多有m個分支(子樹);而最少分支數要看是否為根結點,如果是根結點且不是葉子結點,則至少要有兩個分支非根非葉結點至少有ceil(m/2)個分支,這裡ceil代表向上取整。
2)如果一個結點有n-1個關鍵字,那麼該結點有n個分支。這n-1個關鍵字按照遞增順序排列。
3)每個結點的結構為:
n k1 k2 ... kn
p0 p1 p2 ... pn

其中,n為該結點中關鍵字的個數;ki為該結點的關鍵字且滿足ki<ki+1;pi為該結點的孩子結點指標且滿足pi所指結點上的關鍵字大於ki且小於ki+1,p0所指結點上的關鍵字小於k1,pn所指結點上的關鍵字大於kn。

4)結點內各關鍵字互不相等且按從小到大排列。
5)葉子結點處於同一層;可以用空指標表示,是查詢失敗到達的位置。

注:平衡m叉查詢樹是指每個關鍵字的左側子樹與右側子樹的高度差的絕對值不超過1的查詢樹,其結點結構與上面提到的B-樹結點結構相同,由此可見,B-樹是平衡m叉查詢樹,但限制更強,要求所有葉結點都在同一層。

摘錄了大佬 文哥的學習日記 的例項,原文連結在開篇已經給出。

上面的圖片顯示了一棵B-樹,最底層的葉子結點沒有顯示。我們對上面提到的5條特點進行逐條解釋:
1)結點的分支數等於關鍵字數+1,最大的分支數就是B-樹的階數,因此m階的B-樹中結點最多有m個分支,所以可以看到,上面的一棵樹是一個5-階B-樹。
2)因為上面是一棵5階B-樹,所以非根非葉結點至少要有ceil(5/2)=3個分支。根結點可以不滿足這個條件,圖中的根結點有兩個分支。
3)如果根結點中沒有關鍵字就沒有分支,此時B-樹是空樹,如果根結點有關鍵字,則其分支數比大於或等於2,因為分支數等於關鍵字數+1.
4)上圖中除根結點外,結點中的關鍵字個數至少為2,因為分支數至少為3,分支數比關鍵字數多1,還可以看出結點內關鍵字都是有序的,並且在同一層中,左邊結點內所有關鍵字均小於右邊結點內的關鍵字,例如,第二層上的兩個結點,左邊結點內的關鍵字為15,26,他們均小於右邊結點內的關鍵字39和45.
B-樹一個很重要的特徵是,下層結點內的關鍵字取值總是落在由上層結點關鍵字所劃分的區間內,具體落在哪個區間內可以由指向它的指標看出。例如,第二層最左邊的結點內的關鍵字劃分了三個區間,小於15,15到26,大於26,可以看出其下層中最左邊結點內的關鍵字都小於15,中間結點的關鍵字在15和26之間,右邊結點的關鍵字大於26.
5)上圖中葉子結點都在第四層上,代表查詢不成功的位置。

B-樹上的查詢

(1)將給定key值與根結點關鍵字k[i](k[]為結點內的關鍵字陣列)比較,如果相等,那麼查詢成功。
(2)

  • 若key<k[1],則到p[0]所指示的子樹中進行繼續查詢(p[ ]為結點內的指標陣列),這裡要注意B-樹中每個結點的內部結構。
  • 若key>k[n],則道p[n]所指示的子樹中繼續查詢。
  • 若k[i]<key<k[i+1],則沿著指標p[I]所指示的子樹繼續查詢。

(3)如果,查詢到葉子結點,那麼查詢失敗。

B-樹上的插入

與二叉排序樹一樣,B-樹的建立過程也是將關鍵字逐個插入到樹中的過程。
在進行插入之前,要確定一下每個結點中關鍵字個數的範圍,如果B-樹的階數為m,則結點中關鍵字個數的範圍為 [ceil(m/2)-1,m-1] 個。
對於關鍵字的插入,需要找到插入位置。在B-樹的查詢過程中,當遇到空指標時,則證明查詢不成功,同時也找到了插入位置,即根據空指標可以確定在最底層非葉結點中的插入位置,為了方便,我們稱最底層的非葉結點為終端結點,由此可見,B-樹結點的插入總是落在終端結點上。在插入過程中有可能破壞B-樹的特徵,如新關鍵字的插入使得結點中關鍵字的個數超過規定個數,這是要進行結點的拆分。

接下來,我們以關鍵字序列{1,2,6,7,11,4,8,13,10,5,17,9,16,20,3,12,14,18,19,15}建立一棵5階B-樹,我們將詳細體會B-樹的插入過程。
(1)確定結點中關鍵字個數範圍
由於題目要求建立5階B-樹,因此關鍵字的個數範圍為2~4
(2)根結點最多可以容納4個關鍵字,依次插入關鍵字1、2、6、7後的B-樹如下圖所示:

(3)當插入關鍵字11的時候,發現此時結點中關鍵字的個數變為5,超出範圍,需要拆分,去關鍵字陣列中的中間位置,也就是k[3]=6,作為一個獨立的結點,即新的根結點,將關鍵字6左、右關鍵字分別做成兩個結點,作為新根結點的兩個分支,此時樹如下圖所示:

(4)新關鍵字總是插在葉子結點上,插入關鍵字4、8、13之後樹為:

(5)關鍵字10需要插入在關鍵字8和11之間,此時又會出現關鍵字個數超出範圍的情況,因此需要拆分。拆分時需要將關鍵字10納入根結點中,並將10左右的關鍵字做成兩個新的結點連在根結點上。插入關鍵字10並經過拆分操作後的B-樹如下圖:

(6)插入關鍵字5、17、9、16之後的B-樹如圖所示:

(7)關鍵字20插入在關鍵字17以後,此時會造成結點關鍵字個數超出範圍,需要拆分,方法同上,樹為:

(8)按照上述步驟依次插入關鍵字3、12、14、18、19之後B-樹如下圖所示:

(9)插入最後一個關鍵字15,15應該插入在14之後,此時會出現關鍵字個數超出範圍的情況,則需要進行拆分,將13併入根結點,13併入根結點之後,又使得根結點的關鍵字個數超出範圍,需要再次進行拆分,將10作為新的根結點,並將10左、右關鍵字做成兩個新結點連線到新根結點的指標上,這種插入一個關鍵字之後出現多次拆分的情況稱為連鎖反應,最終形成的B-樹如下圖所示:

B-樹的刪除

對於B-樹關鍵字的刪除,需要找到待刪除的關鍵字,在結點中刪除關鍵字的過程也有可能破壞B-樹的特性,如舊關鍵字的刪除可能使得結點中關鍵字的個數少於規定個數,這是可能需要向其兄弟結點借關鍵字或者和其孩子結點進行關鍵字的交換,也可能需要進行結點的合併,其中,和當前結點的孩子進行關鍵字交換的操作可以保證刪除操作總是發生在終端結點上。

我們用剛剛生成的B-樹作為例子,一次刪除8、16、15、4這4個關鍵字。
(1)刪除關鍵字8、16。關鍵字8在終端結點上,並且刪除後其所在結點中關鍵字的個數不會少於2,因此可以直接刪除。關鍵字16不在終端結點上,但是可以用17來覆蓋16,然後將原來的17刪除掉,這就是上面提到的和孩子結點進行關鍵字交換的操作。這裡不能用15和16進行關鍵字交換,因為這樣會導致15所在結點中關鍵字的個數小於2。因此,刪除8和16之後B-樹如下圖所示:

(2)刪除關鍵字15,15雖然也在終端結點上,但是不能直接刪除,因為刪除後當前結點中關鍵字的個數小於2。這是需要向其兄弟結點借關鍵字,顯然應該向其右兄弟來借關鍵字,因為左兄弟的關鍵字個數已經是下限2.借關鍵字不能直接將18移到15所在的結點上,因為這樣會使得15所在的結點上出現比17大的關鍵字,所以正確的借法應該是先用17覆蓋15,在用18覆蓋原來的17,最後刪除原來的18,刪除關鍵字15後的B-樹如下圖所示:

(3)刪除關鍵字4,4在終端結點上,但是此時4所在的結點的關鍵字個數已經到下限,需要借關鍵字,不過可以看到其左右兄弟結點已經沒有多餘的關鍵字可借。所以就需要進行關鍵字的合併。可以先將關鍵字4刪除,然後將關鍵字5、6、7、9進行合併作為一個結點連結在關鍵字3右邊的指標上,也可以將關鍵字1、2、3、5合併作為一個結點連結在關鍵字6左邊的指標上,如下圖所示:

顯然上述兩種情況下都不滿足B-樹的規定,即出現了非根的雙分支結點,需要繼續進行合併,合併後的B-樹如下圖所示:

有時候刪除的結點不在終端結點上,我們首先需要將其轉化到終端結點上,然後再按上面的各種情況進行刪除。在講述這種情況下的刪除方法之前,要引入一個相鄰關鍵字的概念,對於不在終端結點的關鍵字a,它的相鄰關鍵字為其左子樹中值最大的關鍵字或者其右子樹中值最小的關鍵字。找a的相鄰關鍵字的方法為:沿著a的左指標來到其子樹根結點,然後沿著根結點中最右端的關鍵字的右指標往下走,用同樣的方法一直走到葉結點上,葉結點上的最右端的關鍵字即為a的相鄰關鍵字(這裡找的是a左邊的相鄰關鍵字,我們可以用同樣的思路找到a右邊的相鄰關鍵字)。可以看到下圖中a的相鄰關鍵字是d和e,要刪除關鍵字a,可以用d來取代a,然後按照上面的情況刪除葉子結點上的d即可。

B-樹的應用

為了將大型資料庫檔案儲存在硬碟上,以減少訪問硬碟次數為目的,在此提出了一種平衡多路查詢樹——B-樹結構。由其效能分析可知它的檢索效率是相當高的 為了提高 B-樹效能’還有很多種B-樹的變型,力圖對B-樹進行改進,比如B+樹。

B+樹

B+樹是應檔案系統所需而出的一種B-樹的變型樹。
一棵m階的B+樹和m階的B-樹的差異在於:

  1. 有n棵子樹的結點中含有n個關鍵字。
  2. 所有的葉子結點中包含了全部關鍵字資訊,及指向含這些關鍵字記錄的指標,且葉子結點本身依關鍵字的大小自小而大順序連結。
  3. 所有的非終端結點可以看成是索引部分,結點中僅含有其子樹(根結點)中的最大(或最小)關鍵字。

鍵樹

又稱數字查詢樹,它是一棵度≥2的樹,樹中的每個結點中不是包含一個或幾個關鍵字,而是隻含有組成關鍵字的符號。

例如,若關鍵字為數值,則結點中只包含一個數位;若關鍵字為單詞,則結點中只包含一個字母字元。這種樹會給某種型別關鍵字的表的查詢帶來方便。

雜湊查詢

基本思想

在記錄的儲存地址和它的關鍵字之間建立一個確定的對應關係;這樣,不經過比較,一次存取就能得到所查元素的查詢方法

定義

雜湊函式

在記錄的關鍵字與記錄的儲存地址之間建立的一種對應關係叫雜湊函式。
addr(ai)=H(ki)
其中,ai是表中元素,addr()是取址函式,ki是ai的關鍵字,H()是雜湊函式。

關鍵字集合——H( )——>儲存地址集合

雜湊表

應用雜湊函式,由記錄的關鍵字確定記錄在表中的地址,並將記錄放入此地址,這樣構成的表叫雜湊表。

雜湊查詢

又叫雜湊查詢,利用雜湊函式進行查詢的過程。

雜湊函式的構造方法

直接定址法

  • 構造
    取關鍵字或關鍵字的某個線性函式作雜湊地址,即H(key)=key 或 H(key)=a·key+b
  • 特點
    直接定址法所得地址集合與關鍵字集合大小相等,不會發生衝突
  • 實際中能用這種雜湊函式的情況很少

數字分析法

  • 構造
    對關鍵字進行分析,取關鍵字的若干位或其組合作雜湊地址
  • 適於關鍵字位數比雜湊地址位數大,且可能出現的關鍵字事先知道的情況

平方取中法

  • 構造
    取關鍵字平方後中間幾位作雜湊地址
  • 適於不知道全部關鍵字情況

摺疊法

  • 構造
    將關鍵字分割成位數相同的幾部分,然後取這幾部分的疊加和(捨去進位)做雜湊地址
  • 種類
    移位疊加:將分割後的幾部分低位對齊相加
    間界疊加:從一端沿分割界來回折送,然後對齊相加
  • 適於關鍵字位數很多,且每一位上數字分佈大致均勻情況

除留餘數法

  • 構造
    取關鍵字被某個不大於雜湊表表長m的數p除後所得餘數作雜湊地址,即H(key)=key MOD p,pm
  • 特點
    簡單、常用,可與上述幾種方法結合使用
    p的選取很重要;p選的不好,容易產生同義詞

隨機數法

  • 構造
    取關鍵字的隨機函式值作雜湊地址,即H(key)=random(key)
  • 適於關鍵字長度不等的情況

選取雜湊函式的因素

  1. 計算雜湊函式所需時間
  2. 關鍵字長度
  3. 雜湊表長度(雜湊地址範圍)
  4. 關鍵字分佈情況
  5. 記錄的查詢頻率

處理衝突的方法

開放定址法

  • 方法
    當衝突發生時,形成一個探查序列;沿此序列逐個地址探查,直到找到一個空位置(開放的地址),將發生衝突的記錄放到該地址中,
    即hash(key) = (hash(key)+di)mod TableSize。
    di為增量序列,TableSize為表長。

  • 分類
    線性探測再雜湊:di=1,2,3,……m-1
    二次探測再雜湊:di=1²,-1²,2²,-2²,3²,……±k²(k <= m/2)
    偽隨機探測再雜湊:di=偽隨機數序列

再雜湊法

  • 方法
    構造若干個雜湊函式,當發生衝突時,計算下一個雜湊地址,即:Hi=Rhi(key) i=1,2,……k
    其中:Rhi——不同的雜湊函式
  • 特點
    計算時間增加

鏈地址法

  • 方法
    將所有關鍵字為同義詞的記錄儲存在一個單鏈表中,並用一維陣列存放頭指標。

雜湊查詢過程及分析

雜湊查詢過程

雜湊查詢分析

  • 雜湊查詢過程仍是一個給定值與關鍵字進行比較的過程
  • 評價雜湊查詢效率仍要用ASL
  • 雜湊查詢過程與給定值進行比較的關鍵字的個數取決於:
  1. 雜湊函式
  2. 處理衝突的方法
  3. 雜湊表的填滿因子=表中填入的記錄數/雜湊表長度

雜湊表小結

  • 雜湊方法的查詢效率不依賴於n ,只依賴於負載因子
    α=n/M n為散列表中關鍵字個數,M為散列表表長,散列表檢索的平均檢索長度只隨α 的增大而增加。

  • 雜湊方法的應用限制
    雜湊方法一般不適用於重複關鍵碼值的應用程式
    雜湊方法一般不適用於範圍檢索