Hash碰撞沖突(哈希碰撞):
我們知道,對象Hash的前提是實現equals()和hashCode()兩個方法,那么HashCode()的作用就是保證對象返回唯一hash值,但當兩個對象計算值一樣時,這就發生了碰撞沖突。
當我們對某個元素進行哈希運算,得到一個存儲地址,然后要進行插入的時候,發現已經被其他元素占用了,其實這就是所謂的哈希沖突,也叫哈希碰撞。
哈希沖突如何解決呢?
哈希沖突的解決方案有4種:
1.開放地址法:(再散列法):當關鍵字key的哈希地址p出現沖突時,以p為基礎,產生另一個哈希地址p1,如果p1仍然沖突,再以p為基礎,產生另一個哈希地址,直到找出一個不沖突的哈希地址pi ,將相應元素存入其中。
2.再哈希法: 在發生沖突的時候再用另外一個哈希函數算出哈希值,直到算出的哈希值不同為止。
3.鏈地址法(拉鏈法):例如HashMap。把同一個散列槽(數組的每一個槽)中的所有元素放到一個鏈表中。
4.建立公共溢出區法: 在創建哈希表的同時,再額外創建一個公共溢出區,專門用來存放發生哈希沖突的元素。查找時,先從哈希表查,查不到再去公共溢出區查。
拉鏈法方法:我們拿到一個索引首先計算其在散列函數作用下映射出來的索引,如果索引沒有元素,直接插入;如果有元素,但是key值和我們要插入的數據不一樣,我們就把key value鍵值對插入鏈表頭;
如果存在和我們要插入數據相同key的鍵值對,我們就把value進行更換。
常見的哈希算法
哈希表的組成取決於哈希算法,也就是哈希函數的構成,下面列舉幾種常見的哈希算法。
1) 直接定址法
- 取關鍵字或關鍵字的某個線性函數值為散列地址。
- 即 f(key) = key 或 f(key) = a*key + b,其中a和b為常數。
2) 除留余數法
- 取關鍵字被某個不大於散列表長度 m 的數 p 求余,得到的作為散列地址。
- 即 f(key) = key % p, p < m。這是最為常見的一種哈希算法。
3) 數字分析法
- 當關鍵字的位數大於地址的位數,對關鍵字的各位分布進行分析,選出分布均勻的任意幾位作為散列地址。
- 僅適用於所有關鍵字都已知的情況下,根據實際應用確定要選取的部分,盡量避免發生沖突。
4) 平方取中法
- 先計算出關鍵字值的平方,然后取平方值中間幾位作為散列地址。
- 隨機分布的關鍵字,得到的散列地址也是隨機分布的。
5) 隨機數法
- 選擇一個隨機函數,把關鍵字的隨機函數值作為它的哈希值。
- 通常當關鍵字的長度不等時用這種方法。