散列沖突(哈希碰撞)的解決辦法
相關概念
哈希算法(散列函數)
哈希算法(散列算法)是信息存儲和查詢所用的一項基本技術,它是一種基於Hash函數的文件構造方法,可實現對記錄的快速隨機存取。它把給定的任意長關鍵字映射為一個固定長度的哈希值,一般用於鑒權、認證、加密、索引等。其主要優點是運算簡單,預處理時間較短,內存消耗低,匹配查找速度比較快,便於維護和刷新,支持匹配規則數多等。
什么是哈希碰撞(散列沖突)
Hash算法並不完美,有可能兩個不同的原始值在經過哈希運算后得到同樣的結果, 這樣就是哈希碰撞。
解決辦法
1、開放定址法
所謂的開放定址法就是一旦發生了沖突,就去尋找下一個空的散列地址,只要散列表足夠大,空的散列地址總能找到,並將記錄存入。
fi(key)=(f(key)+di)MOD m (di=1,2,3,…,m-1)
1)線性探測法
di=1,2,3,…,m-1
這種方法的特點是:沖突發生時,順序查看表中下一單元,直到找出一個空單元或查遍全表。
我們把這種解決沖突的開放地址法稱為線性探測法。
2)二次探測法
fi(key)=(f(key)+di)MOD m (di=1²,-1²,2²,-2²,…,q²,-q² (q<=m/2 )
這種方法的特點是:沖突發生時,在表的左右進行跳躍式探測,比較靈活。
增加平方運算的目的是為了不讓關鍵字都聚集在某一塊區域。我們稱這種方法為二次探測法。
3)隨機探測法
還有一種方法是,在沖突時,對於位移量di采用隨機函數計算得到,我們稱之為隨機探測法。
fi(key)=(f(key)+di)MOD m (di是一個隨機數列 )
總之,開放定址法只要在散列表未填滿時,總是能找到不發生沖突的地址,是我們常用的解決沖突的辦法。
2、再散列函數法
事先准備多個散列函數:
fi(key)=RHi(key)( i=1,2,…,k)
當哈希地址Hi=RH1(key)發生沖突時,再計算Hi=RH2(key)……,直到沖突不再產生。這種方法不易產生聚集,但增加了計算時間。
3、鏈地址法(拉鏈法)
思路還可以再換一換,為什么有沖突就非要換地方呢,我們直接就在原地處理行不行呢?於是我們就有了鏈地址法。
將所有關鍵字為同義詞的記錄存儲在一個單鏈表中,我們稱這種表為同義詞子表,在散列表中只存儲所有同義詞子表的頭指針。
對於關鍵字集合{12,67,56,16,25,37, 22,29,15,47,48,34},我們用前面同樣的12為除數,進行除留余數法:
此時,已經不存在什么沖突換址的問題,無論有多少個沖突,都只是在當前位置給單鏈表增加結點的問題。
拉鏈法解決沖突的做法是:將所有關鍵字為同義詞的結點鏈接在同一個單鏈表中。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指針組成的指針數組T[0..m-1]。凡是散列地址為i的結點,均插入到以T[i]為頭指針的單鏈表中。T中各分量的初值均應為空指針。在拉鏈法中,裝填因子α可以大於 1,但一般均取α≤1。
鏈地址法對於可能會造成很多沖突的散列函數來說,提供了絕不會出現找不到地址的保障,當然,這也就帶來了查找時需要遍歷單鏈表的性能損耗。
4、建立公共溢出區
這種方法的基本思想是:將哈希表分為基本表和溢出表兩部分,凡是和基本表發生沖突的元素,一律填入溢出表。
在查找時,對給定值通過散列函數計算出散列地址后,先與基本表的相應位置進行對比,如果相等,則查找成功;如果不相等,則到溢出表去進行順序查找。如果相對於基本表而言,有沖突的數據很少的情況下,公共溢出區的結構對查找性能來說還是非常高的。