1. 程式人生 > >hash表的 構造方法 和 解決衝突的方法

hash表的 構造方法 和 解決衝突的方法

雜湊表是種資料結構,它可以提供快速的插入操作和查詢操作。第一次接觸雜湊表時,它的優點多得讓人難以置信。不論雜湊表中有多少資料,插入和刪除(有時包括側除)只需要接近常量的時間即0(1)的時間級。實際上,這隻需要幾條機器指令。

  對雜湊表的使用者一一人來說,這是一瞬間的事。雜湊表運算得非常快,在計算機程式中,如果需要在一秒種內查詢上千條記錄通常使用雜湊表(例如拼寫檢查器)雜湊表的速度明顯比樹快,樹的操作通常需要O(N)的時間級。雜湊表不僅速度快,程式設計實現也相對容易。

  雜湊表也有一些缺點它是基於陣列的,陣列建立後難於擴充套件某些雜湊表被基本填滿時,效能下降得非常嚴重,所以程式雖必須要清楚表中將要儲存多少資料(或者準備好定期地把資料轉移到更大的雜湊表中,這是個費時的過程)。

  而且,也沒有一種簡便的方法可以以任何一種順序〔例如從小到大〕遍歷表中資料項。如果需要這種能力,就只能選擇其他資料結構。

然而如果不需要有序遍歷資料,井且可以提前預測資料量的大小。那麼雜湊表在速度和易用性方面是無與倫比的。

=================================================================================

雜湊表演算法-雜湊表的概念及作用

  一般的線性表,樹中,記錄在結構中的相對位置是隨機的,即和記錄的關鍵字之間不存在確定的關係,因此,在結構中查詢記錄時需進行一系列和關鍵字的比較。這一類查詢方法建立在“比較“的基礎上,查詢的

效率依賴於查詢過程中所進行的比較次數。

  理想的情況是能直接找到需要的記錄,因此必須在記錄的儲存位置和它的關鍵字之間建立一個確定的對應關係f,使每個關鍵字和結構中一個唯一的儲存位置相對應。

雜湊表最常見的例子是以學生學號為關鍵字的成績表,1號學生的記錄位置在第一條,10號學生的記錄位置在第10條...

如果我們以學生姓名為關鍵字,如何建立查詢表,使得根據姓名可以直接找到相應記錄呢?

雜湊表演算法雜湊表演算法

用上述得到的數值作為對應記錄在表中的位置,得到下表:

雜湊表演算法雜湊表演算法

上面這張表即雜湊表。

如果將來要查李秋梅的成績,可以用上述方法求出該記錄所在位置:

李秋梅:lqm 12+17+13=42 取表中第42條記錄即可。

問題:如果兩個同學分別叫 劉麗 劉蘭 該如何處理這兩條記錄?

這個問題是雜湊表不可避免的,即衝突現象:對不同的關鍵字可能得到同一雜湊地址。

=================================================================================


雜湊表演算法-雜湊表的構造方法

1、直接定址法

取關鍵字或者關鍵字的某個線性函式值作為雜湊地址,即H(Key)=Key或者H(Key)=a*Key+b(a,b為整數),這種雜湊函式也叫做自身函式.如果H(Key)的雜湊地址上已經有值了,那麼就往下一個位置找,知道找到H(Key)的位置沒有值了就把元素放進去.

例如:有一個從1到100歲的人口數字統計表,其中,年齡作為關鍵字,雜湊函式取關鍵字自身。

但這種方法效率不高,時間複雜度是O(1),空間複雜度是O(n),n是關鍵字的個數

雜湊表演算法雜湊表演算法

2、數字分析法

分析一組資料,比如一組員工的出生年月,這時我們發現出生年月的前幾位數字一般都相同,因此,出現衝突的概率就會很大,但是我們發現年月日的後幾位表示月份和具體日期的數字差別很大,如果利用後面的幾位數字來構造雜湊地址,則衝突的機率則會明顯降低.因此數字分析法就是找出數字的規律,儘可能利用這些資料來構造衝突機率較低的雜湊地址.

有學生的生日資料如下:

年.月.日

75.10.03
75.11.23
76.03.02
76.07.12
75.04.21
76.02.15
...

經分析,第一位,第二位,第三位重複的可能性大,取這三位造成衝突的機會增加,所以儘量不取前三位,取後三位比較好。

3、平方取中法

取關鍵字平方後的中間幾位為雜湊地址

4、摺疊法

摺疊法即將關鍵字分割成位數相同的幾部分,最後一部分位數可以不同,然後取這幾部分的疊加和(注意:疊加和時去除進位)作為雜湊地址.數位疊加可以有移位疊加和間界疊加兩種方法.移位疊加是將分割後的每一部分的最低位對齊,然後相加;間界疊加是從一端向另一端沿分割界來回摺疊,然後對齊相加.


將關鍵字分割成位數相同的幾部分(最後一部分的位數可以不同),然後取這幾部分的疊加和(捨去進位)作為雜湊地址,這方法稱為摺疊法。

例如:每一種西文圖書都有一個國際標準圖書編號,它是一個10位的十進位制數字,若要以它作關鍵字建立一個雜湊表,當館藏書種類不到10,000時,可採用此法構造一個四位數的雜湊函式。如果一本書的編號為0-442-20586-4,則:

雜湊表演算法雜湊表演算法

5、除留餘數法

取關鍵字被某個不大於散列表表長m的數p除後所得的餘數為雜湊地址.即H(Key)=Key MOD p,p<=m.不僅可以對關鍵字直接取模,也可在摺疊、平方取中等運算之後取模。對p的選擇很重要,一般取素數或m,若p選得不好,則很容易產生衝突。

取關鍵字被某個不大於雜湊表表長m的數p除後所得餘數為雜湊地址。

H(key)=key MOD p (p<=m)

6、隨機數法

選擇一個隨機函式,取關鍵字的隨機函式值為它的雜湊地址,即

H(key)=random(key) ,其中random為隨機函式。通常用於關鍵字長度不等時採用此法。

=================================================================================


雜湊表演算法-處理衝突的方法

雜湊表處理衝突主要有開放定址法、再雜湊法、鏈地址法(拉鍊法)和建立一個公共溢位區四種方法。

通過構造效能良好的雜湊函式,可以減少衝突,但一般不可能完全避免衝突,因此解決衝突是雜湊法的另一個關鍵問題。建立雜湊表和查詢雜湊表都會遇到衝突,兩種情況下解決衝突的方法應該一致。下面以建立雜湊表為例,說明解決衝突的方法。常用的解決衝突方法有以下四種:


雜湊表演算法

如果兩個同學分別叫 劉麗 劉蘭,當加入劉蘭時,地址24發生了衝突,我們可以以某種規律使用其它的儲存位置,如果選擇的一個其它位置仍有衝突,則再選下一個,直到找到沒有衝突的位置。選擇其它位置的方法有:

1、開放定址法

這種方法也稱再雜湊法,其基本思想是:當關鍵字key的雜湊地址p=H(key)出現衝突時,以p為基礎,產生另一個雜湊地址p1,如果p1仍然衝突,再以p為基礎,產生另一個雜湊地址p2,…,直到找出一個不衝突的雜湊地址pi ,將相應元素存入其中。這種方法有一個通用的再雜湊函式形式:Hi=(H(key)+di)%m   i=1,2,…,n,其中H(key)為雜湊函式,m 為表長,di稱為增量序列。增量序列的取值方式不同,相應的再雜湊方式也不同。主要有以下三種:

(1) 線性探測再雜湊

di=1,2,3,…,m-1

這種方法的特點是:衝突發生時,順序查看錶中下一單元,直到找出一個空單元或查遍全表。

(2)二次探測再雜湊

   di=12,-12,22,-22,…,k2,-k2    ( k<=m/2)

    這種方法的特點是:衝突發生時,在表的左右進行跳躍式探測,比較靈活。

(3)偽隨機探測再雜湊

    di=偽隨機數序列。

具體實現時,應建立一個偽隨機數發生器,(如i=(i+p) % m),並給定一個隨機數做起點。

例如,已知雜湊表長度m=11,雜湊函式為:H(key)= key  %  11,則H(47)=3,H(26)=4,H(60)=5,假設下一個關鍵字為69,則H(69)=3,與47衝突。如果用線性探測再雜湊處理衝突,下一個雜湊地址為H1=(3 + 1)% 11 = 4,仍然衝突,再找下一個雜湊地址為H2=(3 + 2)% 11 = 5,還是衝突,繼續找下一個雜湊地址為H3=(3 + 3)% 11 = 6,此時不再衝突,將69填入5號單元。如果用二次探測再雜湊處理衝突,下一個雜湊地址為H1=(3 + 12)% 11 = 4,仍然衝突,再找下一個雜湊地址為H2=(3 - 12)% 11 = 2,此時不再衝突,將69填入2號單元。如果用偽隨機探測再雜湊處理衝突,且偽隨機數序列為:2,5,9,……..,則下一個雜湊地址為H1=(3 + 2)% 11 = 5,仍然衝突,再找下一個雜湊地址為H2=(3 + 5)% 11 = 8,此時不再衝突,將69填入8號單元。

從上述例子可以看出,線性探測再雜湊容易產生“二次聚集”,即在處理同義詞的衝突時又導致非同義詞的衝突。例如,當表中i, i+1 ,i+2三個單元已滿時,下一個雜湊地址為i, 或i+1 ,或i+2,或i+3的元素,都將填入i+3這同一個單元,而這四個元素並非同義詞。線性探測再雜湊的優點是:只要雜湊表不滿,就一定能找到一個不衝突的雜湊地址,而二次探測再雜湊和偽隨機探測再雜湊則不一定。


Hi=(H(key)+di) MOD m i=1,2,...,k(k<=m-1)

其中m為表長,di為增量序列

如果di值可能為1,2,3,...m-1,稱線性探測再雜湊。

如果di取值可能為1,-1,2,-2,4,-4,9,-9,16,-16,...k*k,-k*k(k<=m/2)

稱二次探測再雜湊

如果di取值可能為偽隨機數列。稱偽隨機探測再雜湊。

例:在長度為11的雜湊表中已填有關鍵字分別為17,60,29的記錄,現有第四個記錄,其關鍵字為38,由雜湊函式得到地址為5,若用線性探測再雜湊,如下:

雜湊表演算法雜湊表演算法

2、再雜湊法

這種方法是同時構造多個不同的雜湊函式:

        Hi=RH1(key),i=1,2,3,…,n.

        當雜湊地址Hi=RH1(key)發生衝突時,再計算Hi=RH2(key)……,直到衝突不再產生。這種方法不易產生聚集,但增加了計算時間


當發生衝突時,使用第二個、第三個、雜湊函式計算地址,直到無衝突時。缺點:計算時間增加。

3、鏈地址法

這種方法的基本思想是將所有雜湊地址為i的元素構成一個稱為同義詞鏈的單鏈表,並將單鏈表的頭指標存在雜湊表的第i個單元中,因而查詢、插入和刪除主要在同義詞鏈中進行。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指標組成的指標陣列T[0..m-1]。凡是雜湊地址為i的結點,均插入到以T[i]為頭指標的單鏈表中。T中各分量的初值均應為空指標。鏈地址法適用於經常進行插入和刪除的情況。

例如,已知一組關鍵字(32,40,36,53,16,46,71,27,42,24,49,64),雜湊表長度為13,雜湊函式為:H(key)= key % 13,則用鏈地址法處理衝突的結果如圖8.27所示:

圖8.27 鏈地址法處理衝突時的雜湊表

本例的平均查詢長度 ASL=(1*7+2*4+3*1)/12=1.5

拉鍊法的優點

與開放定址法相比,拉鍊法有如下幾個優點:

(1)拉鍊法處理衝突簡單,且無堆積現象,即非同義詞決不會發生衝突,因此平均查詢長度較短;

(2)由於拉鍊法中各連結串列上的結點空間是動態申請的,故它更適合於造表前無法確定表長的情況;

(3)開放定址法為減少衝突,要求裝填因子α較小,故當結點規模較大時會浪費很多空間。而拉鍊法中可取α≥1,且結點較大時,拉鍊法中增加的指標域可忽略不計,因此節省空間;

(4)在用拉鍊法構造的散列表中,刪除結點的操作易於實現。只要簡單地刪去連結串列上相應的結點即可。而對開放地址法構造的散列表,刪除結點不能簡單地將被刪結點的空間置為空,否則將截斷在它之後填入散列表的同義詞結點的查詢路徑。這是因為各種開放地址法中,空地址單元(即開放地址)都是查詢失敗的條件。 因此在用開放地址法處理衝突的散列表上執行刪除操作,只能在被刪結點上做刪除標記,而不能真正刪除結點。

拉鍊法的缺點

 拉鍊法的缺點是:指標需要額外的空間,故當結點規模較小時,開放定址法較為節省空間,而若將節省的指標空間用來擴大散列表的規模,可使裝填因子變小,這又減少了開放定址法中的衝突,從而提高平均查詢速度。


將所有關鍵字為同義詞的記錄儲存在同一線性連結串列中。

雜湊表演算法雜湊表演算法

4、建立一個公共溢位區

這種方法的基本思想是:將雜湊表分為基本表和溢位表兩部分,凡是和基本表發生衝突的元素,一律填入溢位表.(注意:在這個方法裡面是把元素分開兩個表來儲存)

衝突太多了怎麼辦?

當衝突太多的時候,我們一般採用的方法時拉鍊法,採用拉鍊法的原因是動態申請空間,至於優點在上面已經闡述了.衝突太多的時候會產生堆積狀態,我們將H(key)相同的關鍵字都統一放到一個鏈裡,當出現衝突的時候我們就把該元素接在連結串列後面,這樣可以避免產生堆積現象,縮短平均查詢長度.

當資料表太小,而資料太多的時候怎麼辦?

當資料表太小資料太多可以通過建立一個溢位表,專門用來存放雜湊表中放不下的記錄.


假設雜湊函式的值域為[0,m-1],則設向量HashTable[0..m-1]為基本表,另外設立儲存空間向量OverTable[0..v]用以儲存發生衝突的記錄。