解決hash衝突的方法

轉自 https://taoyongpan.iteye.com/blog/2401102

hash碰撞衝突:

我們都知道hashCode()的方法是爲了產生不同的hash值,但是當兩個對象的hash一樣時,就發生了碰撞衝突;

解決方法:

我們 常用的解決方法有四種:
①:開放地址法;
②:再hash的方法;
③:拉鍊法;
④:建立公共溢出區法;

開放地址法:

基本思想:當發生地址衝突的時候,按照某種方法繼續探測哈希表中的其他存儲單元,直到找到空位置爲止
所用公式 Hi(key) = [H(key) + di]mod m;其中i = 1、2、3…k(k<m-1),H(key)爲關鍵字key的直接hash地址;M爲hash表的長度;
di爲再次探測時的地址增量;根據di的不同取法,有不同的稱呼;
線性探測再散列:di = 1、2、3、4…k (k<m-1)
二次探測再散列:di = 12,-12,22,-22…k2,-k2 (k<=m/2)
僞隨機再散列:di = 僞隨機數

再hash的方法:

當發生衝突時,使用第二個、第三個、哈希函數計算地址,直到無衝突時。
缺點:計算時間增加。
比如上面第一次按照姓首字母進行哈希,如果產生衝突可以按照姓字母首字母第二位進行哈希,再衝突,第三位,直到不衝突爲止;

拉鍊法:

在HashMap中 就是使用拉鍊法 來解決hash衝突的問題的;
將所有關鍵字爲同義詞的記錄存儲在同一線性鏈表中。如下:
在這裏插入圖片描述

優點:

①拉鍊法處理衝突簡單,且無堆積現象,即非同義詞決不會發生衝突,因此平均查找長度較短;
②由於拉鍊法中各鏈表上的結點空間是動態申請的,故它更適合於造表前無法確定表長的情況;
③開放定址法爲減少衝突,要求裝填因子α較小,故當結點規模較大時會浪費很多空間。而拉鍊法中可取α≥1,且結點較大時,拉鍊法中增加的指針域可忽略不計,因此節省空間;
④在用拉鍊法構造的散列表中,刪除結點的操作易於實現。只要簡單地刪去鏈表上相應的結點即可。而對開放地址法構造的散列表,刪除結點不能簡單地將被刪結點的空間置爲空,否則將截斷在它之後填人散列表的同義詞結點的查找路徑。這是因爲各種開放地址法中,空地址單元(即開放地址)都是查找失敗的條件。因此在用開放地址法處理衝突的散列表上執行刪除操作,只能在被刪結點上做刪除標記,而不能真正刪除結點。

缺點:

指針需要額外的空間,故當結點規模較小時,開放定址法較爲節省空間,而若將節省的指針空間用來擴大散列表的規模,可使裝填因子變小,這又減少了開放定址法中的衝突,從而提高平均查找速度。

建立公共溢出區:

建立公共溢出區的基本思想是:假設哈希函數的值域是[1,m-1],則設向量HashTable[0…m-1]爲基本表,每個分量存放一個記錄,另外設向量OverTable[0…v]爲溢出表,所有關鍵字和基本表中關鍵字爲同義詞的記錄,不管它們由哈希函數得到的哈希地址是什麼,一旦發生衝突,都填入溢出表。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章