Hash沖突就是,不同的數據元素關鍵字K,計算出的哈希值相同,此時兩個或多個數據,對應同一個存儲地址,即產生沖突。
Hash沖突解決辦法:
- 開放定址法
- 再哈希法
- 鏈地址法
- 建立公共溢出區
開放定址法
使用某種探測算法在散列表中尋找下一個空的散列地址,只要散列表足夠大,空的散列地址總能找到。就是即使key產生hash沖突,也不會形成鏈表,而是將所有元素都存入哈希表里。發生hash沖突時,就以當前地址為基准,進行再尋址的方法去尋址下一個地址,直到找到一個為空的地址為止。
1.線性探查:發生hash沖突時,順序查找下一個位置,直到找到一個空位置(固定步長1探測)
2.二次探查:在發生hash沖突時,在表的左右位置進行按一定步長跳躍式探測(固定步長n探測)
3.偽隨機探測:在發生hash沖突時,根據公式生成一個隨機數,作為此次探測空位置的步長(隨機步長n探測)。
再哈希法
這種方式是同時構造多個哈希函數,當產生沖突時,計算另一個哈希函數的值。
這種方法不易產生聚集,但增加了計算時間。
鏈地址法(拉鏈法)
jdk1.8 中HashMap,ConcurrentHashMap都是采用這個方法,使用鏈表來保存發生hash沖突的key,即不同的key有一樣的hash值,將這些發生沖突的 value 組成一個單向鏈表(只有next指針,沒有pre指針)
static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next;
注意:最壞的就是hash值全都映射在同一個地址上,這樣哈希表就會退化成鏈表
jdk1.8采用紅黑樹解決這種情況
建立公共溢出區
將哈希表分為基本表和溢出表兩部分,為所有發生hash沖突的關鍵字記錄一個公共的溢出區來存放。在查找的時候,先與哈希表的相應位置比較,如果查找成功,則返回。否則去公共溢出區按順序一一查找。在沖突數據少時性能好,沖突數據多的時候耗時
優缺點比較:
開放散列(open hashing)/ 拉鏈法(針對桶鏈結構)
優點:
在總數頻繁變動的時候可以節省開銷,避免了動態調整;
記錄存儲在節點里,動態分布,避免了指針的開銷
刪除時候比較方便
缺點:
因為存儲是動態的,所以在查詢的時候跳轉需要更多的時間的開銷
在key-value可以預知,以及沒有后續增改操作時候,封閉散列性能優於開放散列
不容易序列化
封閉散列(closed hashing)/ 開放定址法
優點:
容易序列化
如果可以預知數據總數,可以創建完美哈希數列
缺點:
存儲的記錄數目不能超過桶組數,在交互時候會非常麻煩
使用探測序列,計算時間成本過高
刪除的時候比較麻煩
————————————————
版權聲明:本文為CSDN博主「CommunicationGo」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/DxhToStage/article/details/103991195