《算法導論》學習之旅-第十一章-散列表


序言

許多應用需要一種動態集合結構,他至少支持插入,查找,刪除等字典操作。而散列表就是一種實現字典操作的有效數據結構。

直接尋址表

當關鍵字的全域U比較小時,直接尋址是一種簡單而有效的技術。爲表示動態集合,我們使用了一個數組(也稱爲直接尋址表),記爲T[0…m-1],其中每一個位置,稱爲
在這裏插入圖片描述
運用了直接尋址表,幾個字典操作就變得相對簡單:

DIRECT-ADDRESS-SEARCH(T, k)
	return T[K]

DIRECT-ADDRESS-INSERT(T, x)
	T[x.key] = x

DIRECT-ADDRESS-DELETE(T, x)
	T[x.key] = NIL

上述的每一個操作都只需O(1)時間。
對於某些應用,直接尋址表本身就可以存放動態集合中的元素。也就是說,並不把每個元素的關鍵字及其衛星數據都放在直接尋址表外部的一個對象中,再由表中某個槽的指針指向該對象,而是直接把該對象存放在表的槽中,從而節省了空間。我們使用對象內的一-個特殊關鍵字來表明該槽爲空槽。而且,通常不必存儲該對象的關鍵字屬性,因爲如果知道一個對象在表中的下標,就可以得到它的關鍵字。然而,如果不存儲關鍵字,我們就必須有某種方法來確定某個槽是否爲空。

散列表

直接尋址技術存在着較大的弊端:如果全域很大,但是分配的有效的關鍵字集合K相對於U來說可能很小,那個分配給T的絕大部分空間就可能會被浪費掉。
在直接尋址方式下,具有關鍵字k的元素被放在槽k中。在散列方式下,該元素被放在槽h(k)中,即利用散列函數,由關鍵字k計算出槽的位置。這裏函數h將關鍵字的全域U映射到散列表T[0…m-1]的槽位上:
在這裏插入圖片描述
由於兩個關鍵字可能映射到同一個槽中。那麼這種情況叫做衝突。下面兩種方法可以解決該衝突:鏈接法開放尋址法

通過鏈接法解決衝突

在連接表中,把散列在同一槽中的所有元素都放在一個鏈表中,槽j中有一個指針,它指向存儲所有的散列到j的元素的鏈表的表頭;如果不存在這方的元素,則槽內就是NIL。
在這裏插入圖片描述
針對鏈接法散列的分析,有以下兩條定理:
**定理11.1:**在簡單均勻散列的假設下,對於用鏈接法解決衝突的散列表,一次不成功查找的平均時間爲O(1+α)
**定理11.2:**在簡單均勻散列的假設下,對於用鏈接法解決衝突的散列表,一次成功查找的平均時間爲O(1+α)

散列函數

本節將會討論一些關於如何設計好的散列函數,並介紹三種具體方法。
一個好的散列函數具有以下特點:

滿足簡單均勻散列假設:每個關鍵字都被等可能地散列到m個槽位中的任何一個,並與其它關鍵字已散列到哪個槽位無關。遺憾的是一般無法檢查這一條件是否成立,因爲很少能知道關鍵字的概率分佈,而且各個關鍵字可能不是完全獨立的。

除法散列法

在用來設計散列表函數的除法散列法中,通過取k除以m的餘數,將關鍵字k映射到m個槽中的某一個上,即散列函數爲:
h(k) = k mod m
例如, 如果散列表的大小爲m = 12, 所給的關鍵字爲k = 100, 則h(k) = 4.由於只需要做一次出發操作,所以除法散列法是非常快的。使用除數散列法的時候,對於m的選擇要慎重。比如m不應該是2的冪。否則如果m = 2p,則h(k)就是k的p個最低位數字(二進制)。除非已經知道關鍵字的最低p位數的排列是等可能的,否則在設計散列函數時,應該考慮關鍵字的所有位。一個不太接近2的整數冪的素數是m的一個比較好的選擇。

乘法散列法

h(k) = m(kA mod 1)

第一步,用關鍵字k乘以常數A(0<A<1),提取KA的小數部分(kA mod 1)。
第二步,用m乘以這個值。

在乘法散列法中,m的選擇不是關鍵,一般選擇m爲2的某個次冪。

全域散列表

給定一組散列函數H,每次進行散列時候從H中隨機的選擇一個散列函數h,使得h獨立於要存儲的關鍵字。全域散列函數類的平均性能是比較好的。

開放尋址法

開放定址法是使用某種探測技術在哈希表中形成探測序列,當衝突發生時,沿此序列逐個單元地查找,直到找到空閒單元爲止。按照形成探測序列的方法不同,可以將開放定址法分爲線性探測法、平方探測法,雙哈希函數探測法。

線性探測法

線性探測法是從發生衝突的地址d開始,得到一個探測序列:

d, d+1, d+2, … , m-1, 0, 1, …, d-1 (m爲表長)

在每次查找中,若探測到的單元爲空閒單元便不再往下探查,把關鍵字插入該單元。
線性探測法的公式爲:
h(k,i) = (h’(k) 十i) mod m(1 <= i <= m-1)
利用線性探查法解決衝突時,會發生聚集現象。當表中第i, i+1, … , i+k位置上已有結點時,一個哈希地址爲i, i+1, … , i+k+1的結點都將插入位置i+k+1上。把這種哈希地址不同的結點爭奪同一個後繼哈希地址的現象成爲聚集。這將造成不是同義詞的結點也處在同一個探測序列之中,從而增加了探測序列的長度,增加了查找時間。

平方探測法

平方探測法是從發生衝突的地址d開始,得到一個探測序列:
d, d+20, d-20, d+21, d+21, … ,
平方探測法的探測序列跳躍式地散列在整個哈希表中可以減少聚集現象的發生。該方法的缺點是不能夠探測到整個哈希地址空間。

雙重散列法

雙重散列是用於開放尋址法的最好方法之一,因爲它所產生的排列具有隨機選擇排列的許多特性。雙重散列採用如下形式的散列函數:
h(k,i) = (h1(k) + ih2 (k) ) mod m
在雙重散列中要求h1(k) 與m互素,這樣才能發生衝突的同義詞地址均勻地分佈在整個哈希表中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章