解決雜湊衝突的三種方式

2021-10-23 13:39:40 字數 1506 閱讀 9857

開放位址法有個非常關鍵的特徵,就是所有輸入的元素全部存放在雜湊表裡,也就是說,位桶的實現是不需要任何的鍊錶來實現的,換句話說,也就是這個雜湊表的裝載因子不會超過1。它的實現是在插入乙個元素的時候,先通過雜湊函式進行判斷,若是發生雜湊衝突,就以當前位址為基準,根據再定址的方法(探查序列),去尋找下乙個位址,若發生衝突再去尋找,直至找到乙個為空的位址為止。

有幾種常用的探查序列的方法:

線性探查

di=1,2,3,…,m-1;這種方法的特點是:衝突發生時,順序檢視表中下一單元,直到找出乙個空單元或查遍全表。

(使用例子:threadlocal裡面的threadlocalmap)

二次探查

di=12,-12,22,-22,…,k2,-k2 ( k<=m/2 );這種方法的特點是:衝突發生時,在表的左右進行跳躍式探測,比較靈活。

偽隨機探測

di=偽隨機數序列;具體實現時,應建立乙個偽隨機數發生器,(如i=(i+p) % m),生成乙個位隨機序列,並給定乙個隨機數做起點,每次去加上這個偽隨機數++就可以了。

再雜湊法其實很簡單,就是再使用雜湊函式去雜湊乙個輸入的時候,輸出是同乙個位置就再次雜湊,直至不發生衝突位置

缺點:每次衝突都要重新雜湊,計算時間增加。

hashmap,hashset其實都是採用的拉鍊法來解決雜湊衝突的,就是在每個位桶實現的時候,我們採用鍊錶(jdk1.8之後採用鍊錶+紅黑樹)的資料結構來去訪問發生雜湊衝突的輸入域的關鍵字(也就是被雜湊函式對映到同乙個位桶上的關鍵字)。首先來看使用拉鍊法解決雜湊衝突的幾個操作:

①插入操作:在發生雜湊衝突的時候,我們輸入域的關鍵字去對映到位桶(實際上是實現位桶的這個資料結構,鍊錶或者紅黑樹)中去的時候,我們先檢查帶插入元素x是否出現在表中,很明顯,這個查詢所用的次數不會超過裝載因子(n/m:n為輸入域的關鍵字個數,m為位桶的數目),它是個常數,所以插入操作的最壞時間複雜度為o(1)的。

②查詢操作:和①一樣,在發生雜湊衝突的時候,我們去檢索的時間複雜度不會超過裝載因子,也就是檢索資料的時間複雜度也是o(1)的

③刪除操作:如果在拉鍊法中我們想要使用鍊錶這種資料結構來實現位桶,那麼這個鍊錶一定是雙向鍊錶,因為在刪除乙個元素x的時候,需要更改x的前驅元素的next指標的屬性,把x從鍊錶中刪除。這個操作的時間複雜度也是o(1)的。

與開放定址法相比,拉鍊法有如下幾個優點:

①拉鍊法處理衝突簡單,且無堆積現象,即非同義詞決不會發生衝突,因此平均查詢長度較短;

②由於拉鍊法中各煉表上的結點空間是動態申請的,故它更適合於造表前無法確定表長的情況;

③開放定址法為減少衝突,要求裝填因子α較小,故當結點規模較大時會浪費很多空間。而拉鍊法中可取α≥1,且結點較大時,拉鍊法中增加的指標域可忽略不計,因此節省空間;

④在用拉鍊法構造的雜湊表中,刪除結點的操作易於實現。只要簡單地刪去鍊錶上相應的結點即可。

拉鍊法的缺點

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

使用例子:hashmap

解決雜湊衝突的三種方法

上篇博文我們舉的例子,hashmap,hashset其實都是採用的拉鍊法來解決雜湊衝突的,就是在每個位桶實現的時候,我們採用鍊錶 jdk1.8之後採用鍊錶 紅黑樹 的資料結構來去訪問發生雜湊衝突的輸入域的關鍵字 也就是被雜湊函式對映到同乙個位桶上的關鍵字 首先來看使用拉鍊法解決雜湊衝突的幾個操作 插...

解決事件衝突的三種函式

自定義布局package com.yztc.eventdemo import android.content.context import android.util.attributeset import android.util.log import android.view.motioneven...

雜湊(hash)表以及解決衝突的方式

把查詢表中的關鍵字對映成該關鍵字對應位址的函式,雜湊函式可能會把兩個或兩個以上的不同關鍵字對映到同一位址,稱這種情況為衝突,這些發生碰撞的不同關鍵字成為同義詞。1 直接定址法 直接取關鍵字的摸個現行函式值為雜湊位址,雜湊函式為h key a key b,其中a和b是常數,這種方法最簡單,並且不會產生...