1.基本概念
哈希算法:根據設定的哈希函數H(key)和處理沖突方法將一組關鍵字映象到一個有限的地址區間上的算法。也稱為散列算法、雜湊算法。
哈希表:數據經過哈希算法之后得到的集合。這樣關鍵字和數據在集合中的位置存在一定的關系,可以根據這種關系快速查詢。
非哈希表:與哈希表相對應,集合中的 數據和其存放位置沒任何關聯關系的集合。
由此可見,哈希算法是一種特殊的算法,能將任意數據散列后映射到有限的空間上,通常計算機軟件中用作快速查找或加密使用。
哈希沖突:由于哈希算法被計算的數據是無限的,而計算后的結果范圍有限,因此總會存在不同的數據經過計算后得到的值相同,這就是哈希沖突。
2.解決哈希沖突的方法
解決哈希沖突的方法一般有:開放定址法、鏈地址法(拉鏈法)、再哈希法、建立公共溢出區等方法。
2.1 開放定址法
從發生沖突的那個單元起,按照一定的次序,從哈希表中找到一個空閑的單元。然后把發生沖突的元素存入到該單元的一種方法。開放定址法需要的表長度要大于等于所需要存放的元素。
在開放定址法中解決沖突的方法有:線行探查法、平方探查法、雙散列函數探查法。
開放定址法的缺點在于刪除元素的時候不能真的刪除,否則會引起查找錯誤,只能做一個特殊標記。只到有下個元素插入才能真正刪除該元素。
2.1.1 線行探查法
線行探查法是開放定址法中最簡單的沖突處理方法,它從發生沖突的單元起,依次判斷下一個單元是否為空,當達到最后一個單元時,再從表首依次判斷。直到碰到空閑的單元或者探查完全部單元為止。
可以參考csdn上flash對該方法的演示:
http://student.zjzk.cn/course_ware/data_structure/web/flash/cz/kfdzh.swf
2.1.2 平方探查法
平方探查法即是發生沖突時,用發生沖突的單元d[i], 加上 12、 22等。即d[i] + 12,d[i] + 22, d[i] + 32...直到找到空閑單元。
在實際操作中,平方探查法不能探查到全部剩余的單元。不過在實際應用中,能探查到一半單元也就可以了。若探查到一半單元仍找不到一個空閑單元,表明此散列表太滿,應該重新建立。
2.1.3 雙散列函數探查法
這種方法使用兩個散列函數hl和h2。其中hl和前面的h一樣,以關鍵字為自變量,產生一個0至m—l之間的數作為散列地址;h2也以關鍵字為自變量,產生一個l至m—1之間的、并和m互素的數(即m不能被該數整除)作為探查序列的地址增量(即步長),探查序列的步長值是固定值l;對于平方探查法,探查序列的步長值是探查次數i的兩倍減l;對于雙散列函數探查法,其探查序列的步長值是同一關鍵字的另一散列函數的值。
2.2 鏈地址法(拉鏈法)
鏈接地址法的思路是將哈希值相同的元素構成一個同義詞的單鏈表,并將單鏈表的頭指針存放在哈希表的第i個單元中,查找、插入和刪除主要在同義詞鏈表中進行。鏈表法適用于經常進行插入和刪除的情況。
如下一組數字,(32、40、36、53、16、46、71、27、42、24、49、64)哈希表長度為13,哈希函數為H(key)=key%13,則鏈表法結果如下:
0
1 -> 40 -> 27 -> 53
2
3 -> 16 -> 42
4
5
6 -> 32 -> 71
7 -> 46
8
9
10 -> 36 -> 49
11 -> 24
12 -> 64
注:在java中,鏈接地址法也是HashMap解決哈希沖突的方法之一,jdk1.7完全采用單鏈表來存儲同義詞,jdk1.8則采用了一種混合模式,對于鏈表長度大于8的,會轉換為紅黑樹存儲。
2.3 再哈希法
就是同時構造多個不同的哈希函數:
Hi = RHi(key) i= 1,2,3 ... k;
當H1 = RH1(key) 發生沖突時,再用H2 = RH2(key) 進行計算,直到沖突不再產生,這種方法不易產生聚集,但是增加了計算時間。
2.4 建立公共溢出區
將哈希表分為公共表和溢出表,當溢出發生時,將所有溢出數據統一放到溢出區。