Hash衝突:
理解Hash衝突前,先了解一下Hash函數
哈希函數
數據元素的存儲地址,是根據數據的關鍵字K通過一定的函數關係計算得出,這個函數關係即稱哈希函數。
Hash衝突就是,不同的數據元素關鍵字K,計算出的哈希值相同,此時兩個或多個數據,對應同一個存儲地址,即產生衝突。
Hash衝突解決辦法:
- 開放定址法
- 再哈希法
- 鏈地址法
- 建立公共溢出區
開放定址法
使用某種探測算法在散列表中尋找下一個空的散列地址,只要散列表足夠大,空的散列地址總能找到。按照探測序列的方法,一般將開放地址法區分爲線性探查法(順序的查看下一個單元)、二次探查法(在表的左右進行跳躍式探測)、雙重散列法(雙哈希函數,先用第一個函數 f(key) 對關鍵碼計算哈希地址,一旦產生地址衝突,再用第二個函數 g(key) 確定移動的步長因子,最後通過步長因子序列由探測函數尋找空的哈希地址)、僞隨機探測再散列建立一個僞隨機數發生器,並給一個隨機數作爲起點()等。
** 再哈希法**
這種方式是同時構造多個哈希函數,當產生衝突時,計算另一個哈希函數的值。
這種方法不易產生聚集,但增加了計算時間。
鏈地址法
將所有哈希地址相同的都鏈接在同一個鏈表中 ,因而查找、插入和刪除主要在同義詞鏈中進行。鏈地址法適用於經常進行插入和刪除的情況。
注意:最壞的就是hash值全都映射在同一個地址上,這樣哈希表就會退化成鏈表
jdk1.8採用紅黑樹解決這種情況
建立公共溢出區
將哈希表分爲基本表和溢出表兩部分,凡是和基本表發生衝突的元素,一律填入溢出表。
優缺點比較:
開放散列(open hashing)/ 拉鍊法(針對桶鏈結構)
優點:
在總數頻繁變動的時候可以節省開銷,避免了動態調整;
記錄存儲在節點裏,動態分佈,避免了指針的開銷
刪除時候比較方便
缺點:
因爲存儲是動態的,所以在查詢的時候跳轉需要更多的時間的開銷
在key-value可以預知,以及沒有後續增改操作時候,封閉散列性能優於開放散列
不容易序列化
封閉散列(closed hashing)/ 開放定址法
優點:
容易序列化
如果可以預知數據總數,可以創建完美哈希數列
缺點:
存儲的記錄數目不能超過桶組數,在交互時候會非常麻煩
使用探測序列,計算時間成本過高
刪除的時候比較麻煩