本文轉自https://blog.csdn.net/lyp_558/article/details/49499035
哈希衝突詳解
我喜歡用問答的形式來學習,這樣可以明確許多不明朗的問題。
-
什麼是哈希衝突?
比如我們要去買房子,本來已經看好的房子卻被商家告知那間房子已經被其他客戶買走了。這就是生活中實實在在的衝突問題。
同樣的當數據插入到哈希表時,不同key值產生的h(key)卻是相等的,這個時候就產生了衝突。這個時候就要解決這個問題。
-
怎麼解決哈希衝突?
方法1:拉鍊法
方法2:開地址法 -
何爲拉鍊法?
拉鍊法是解決哈希衝突的一種行之有效的方法,某些哈希地址可以被多個關鍵字值共享,這樣可以針對每個哈希地址建立一個單鏈表。
在拉鍊(單鏈表)的哈希表中搜索一個記錄是容易的,首先計算哈希地址,然後搜索該地址的單鏈表。
在插入時應保證表中不含有與該關鍵字值相同的記錄,然後按在有序表中插入一個記錄的方法進行。針對關鍵字值相同的情況,現行的處理方法是更新該關鍵字值中的內容。
刪除關鍵字值爲k的記錄,應先在該關鍵字值的哈希地址處的單鏈表中找到該記錄,然後刪除之。
-
什麼是開地址法?
首先該方法並不建立鏈表。哈希表由M個元素組成,其地址從0到M-1。我們通過從空表開始,逐個向表中插入新記錄的方式建立散列表。
插入關鍵字值爲key的新紀錄的方法是:
從h(key)開始,按照某種規定的次序探查插入新記錄的空位置。h(key)被稱爲基位置。如果h(key)已經被佔用,那麼需要用一種解決衝突的策略來確定如何探查下一個空位置,所以這種方法又稱爲空缺編址法。
根據不同的解決衝突的策略,可以產生不同的需要被檢查的位置序列,稱爲 探查序列。
根據生成的探查序列的不同規則,可以有 線性探查法、僞隨機探查法、二次探查法 和 雙散列法等開址方法。 -
線性探查法詳解
缺點:線性探查法在情況不好的時候導致許多記錄在散列表中連成一片,從而使探查次數增加,影響搜索效率。這種現象稱爲基本聚集。
線性探查法是一種簡單的開地址方法,它使用下列循環探查序列:
h(key),h(key)+1,...,M-1,0,...,h(key)-1
從基位h(key)開始探查該位置是否被佔用,即是否爲空位置。
如果被佔用,則繼續探查位置h(key)+1,若該位置也已佔用,再根據探查序列中的規定繼續檢查下一個位置。
因此,探查序列爲:h(i) = (h(x)+i) % M (i=0,1,2,...,M-1)
-
僞隨機法詳解
僞隨機法是爲了消除線性探查的基本聚集而提出來的方法。其基本思想是建立一個僞隨機數發生器。當發生衝突時,就利用僞隨機數發生器計算下一個探查位置。僞隨機數發生器有不同的構造。
一個比較簡單的僞隨機數產生方法:
y(0) = h(key) y(i+1) = (y(i)+p) % M (i=0,1,2,...) 式中,y(0)爲僞隨機數發生器的初值,M爲哈希表的長度, P爲與M接近的素數。
-
二次探查法詳解
二次探查法也能夠消除基本聚集,雖然僞隨機數法和二次探查法都能夠消除基本聚集。但是如果兩個關鍵字值有相同的基本位置,那麼它們就會有相同的探查序列。這是因爲僞隨機數法和二次探查產生的探查序列是基位置的函數,而不是原來關鍵字的函數,因此由產生了二次聚集的問題。
- 雙散列法詳解
使用雙散列方法可以避免二級聚集。雙散列法使用兩個散列函數,第一個散列函數計算探針序列的起始值,第二個散列函數計算下一個位置的探查步長。