解決hash衝突的三個方法

經過構造性能良好的哈希函數,能夠減小衝突,但通常不可能徹底避免衝突,所以解決衝突是哈希法的另外一個關鍵問題。建立哈希表和查找哈希表都會遇到衝突,兩種狀況下解決衝突的方法應該一致。下面以建立哈希表爲例,說明解決衝突的方法。經常使用的解決衝突方法有如下四種:數組

開放定址法

這種方法也稱再散列法,其基本思想是:當關鍵字key的哈希地址p=Hkey)出現衝突時,以p爲基礎,產生另外一個哈希地址p1,若是p1仍然衝突,再以p爲基礎,產生另外一個哈希地址p2,直到找出一個不衝突的哈希地址pi 將相應元素存入其中。這種方法有一個通用的再散列函數形式:ide

Hi=Hkey+di% m   i=12…,n函數

其中Hkey)爲哈希函數,爲表長,di稱爲增量序列。增量序列的取值方式不一樣,相應的再散列方式也不一樣。主要有如下三種:性能

線性探測再散列

dii=123m-1spa

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

二次探測再散列

di=12-1222-22k2-k2    ( k<=m/2 )orm

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

僞隨機探測再散列

di=僞隨機數序列。內存

 

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

例如,已知哈希表長度m=11,哈希函數爲:Hkey= key  %  11,則H47=3H26=4H60=5,假設下一個關鍵字爲69,則H69=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號單元

若是用僞隨機探測再散列處理衝突,且僞隨機數序列爲:259……..,則下一個哈希地址爲H1=3 + 2% 11 = 5,仍然衝突,再找下一個哈希地址爲H2=3 + 5% 11 = 8,此時再也不衝突,將69填入8號單元

再哈希法

這種方法是同時構造多個不一樣的哈希函數:

Hi=RH1key  i=12k

當哈希地址Hi=RH1key)發生衝突時,再計算Hi=RH2key)……,直到衝突再也不產生。這種方法不易產生彙集,但增長了計算時間。

鏈地址法

這種方法的基本思想是將全部哈希地址爲i的元素構成一個稱爲同義詞鏈的單鏈表,並將單鏈表的頭指針存在哈希表的第i個單元中,於是查找、插入和刪除主要在同義詞鏈中進行。鏈地址法適用於常常進行插入和刪除的狀況。

 

創建公共溢出區

這種方法的基本思想是:將哈希表分爲基本表和溢出表兩部分,凡是和基本表發生衝突的元素,一概填入溢出表。

 


優缺點

開放散列(open hashing)/ 拉鍊法(針對桶鏈結構)

1)優勢: ①對於記錄總數頻繁可變的狀況,處理的比較好(也就是避免了動態調整的開銷)因爲記錄存儲在結點中,而結點是動態分配,不會形成內存的浪費,因此尤爲適合那種記錄自己尺寸(size)很大的狀況,由於此時指針的開銷能夠忽略不計了刪除記錄時,比較方便,直接經過指針操做便可
 
2)缺點: ①存儲的記錄是隨機分佈在內存中的,這樣在查詢記錄時,相比結構緊湊的數據類型(好比數組),哈希表的跳轉訪問會帶來額外的時間開銷 ②若是全部的 key-value 對是能夠提早預知,並以後不會發生變化時(即不容許插入和刪除),能夠人爲建立一個不會產生衝突的完美哈希函數(perfect hash function),此時封閉散列的性能將遠高於開放散列 ③因爲使用指針,記錄不容易進行序列化(serialize)操做

封閉散列(closed hashing)/ 開放定址法

1)優勢: ①記錄更容易進行序列化(serialize)操做 ②若是記錄總數能夠預知,能夠建立完美哈希函數,此時處理數據的效率是很是高的
 
2)缺點: ①存儲記錄的數目不能超過桶數組的長度,若是超過就須要擴容,而擴容會致使某次操做的時間成本飆升,這在實時或者交互式應用中可能會是一個嚴重的缺陷 ②使用探測序列,有可能其計算的時間成本太高,致使哈希表的處理性能下降 ③因爲記錄是存放在桶數組中的,而桶數組必然存在空槽,因此當記錄自己尺寸(size)很大而且記錄總數規模很大時,空槽佔用的空間會致使明顯的內存浪費 ④刪除記錄時,比較麻煩。好比須要刪除記錄a,記錄b是在a以後插入桶數組的,可是和記錄a有衝突,是經過探測序列再次跳轉找到的地址,因此若是直接刪除a,a的位置變爲空槽,而空槽是查詢記錄失敗的終止條件,這樣會致使記錄b在a的位置從新插入數據前不可見,因此不能直接刪除a,而是設置刪除標記。這就須要額外的空間和操做。
相關文章
相關標籤/搜索