開放尋址法VS鏈表法

                                開放尋址法VS鏈表法

 

開放尋址法


只用數組一種數據結構存儲,繼承了數組的優點,對CPU緩衝友好,易於序列化。但是對內存的利⽤率並不如鏈表法,且衝突的代價更高。當數據量⽐較⼩、裝載因⼦⼩的時候,適合採⽤開放尋址法。這也是Java中的ThreadLocalMap使⽤開放尋址法解決散列衝突的原因。

鏈表法


鏈表法對內存的利⽤率⽐開放尋址法要⾼。因爲鏈表結點可以在需要的時候再創建,並不需要像開放尋址法那樣事先申請好。鏈表法⽐起開放尋址法,對⼤裝載因⼦的容忍度更⾼。基於鏈表的散列衝突處理⽅法⽐較適合存儲⼤對象、⼤數據量的散列表,⽽且,⽐起開放尋址法,它更加靈活,⽀持更多的優化策略,⽐如⽤紅⿊樹代替鏈表。

示例

 

在實際應用中,無論如何構造哈希函數,衝突是無法完全避免的。

1 開放地址法 


這個方法的基本思想是:當發生地址衝突時,按照某種方法繼續探測哈希表中的其他存儲單元,直到找到空位置爲止。這個過程可用下式描述:
H i ( key ) = ( H ( key )+ d i ) mod m ( i = 1,2,…… , k ( k ≤ m – 1)) 
其中: H ( key ) 爲關鍵字 key 的直接哈希地址, m 爲哈希表的長度, di 爲每次再探測時的地址增量。 
採用這種方法時,首先計算出元素的直接哈希地址 H ( key ) ,如果該存儲單元已被其他元素佔用,則繼續查看地址爲 H ( key ) + d 2 的存儲單元,如此重複直至找到某個存儲單元爲空時,將關鍵字爲 key 的數據元素存放到該單元。 
增量 d 可以有不同的取法,並根據其取法有不同的稱呼:
( 1 ) d i = 1 , 2 , 3 , …… 線性探測再散列;
( 2 ) d i = 1^2 ,- 1^2 , 2^2 ,- 2^2 , k^2, -k^2…… 二次探測再散列;
( 3 ) d i = 僞隨機序列 僞隨機再散列; 

例1設有哈希函數 H ( key ) = key mod 7 ,哈希表的地址空間爲 0 ~ 6 ,對關鍵字序列( 32 , 13 , 49 , 55 , 22 , 38 , 21 )按線性探測再散列和二次探測再散列的方法分別構造哈希表。
解:
( 1 )線性探測再散列:
32 % 7 = 4 ; 13 % 7 = 6 ; 49 % 7 = 0 ;
55 % 7 = 6 發生衝突,下一個存儲地址( 6 + 1 )% 7 = 0 ,仍然發生衝突,再下一個存儲地址:( 6 + 2 )% 7 = 1 未發生衝突,可以存入。
22 % 7 = 1 發生衝突,下一個存儲地址是:( 1 + 1 )% 7 = 2 未發生衝突;
38 % 7 = 3 ;
21 % 7 = 0 發生衝突,按照上面方法繼續探測直至空間 5 ,不發生衝突,所得到的哈希表對應存儲位置:
下標: 0 1 2 3 4 5 6
49 55 22 38 32 21 13
( 2 )二次探測再散列:
下標: 0 1 2 3 4 5 6
49 22 21 38 32 55 13
   注意:對於利用開放地址法處理衝突所產生的哈希表中刪除一個元素時需要謹慎,不能直接地刪除,因爲這樣將會截斷其他具有相同哈希地址的元素的查找地址,所以,通常採用設定一個特殊的標誌以示該元素已被刪除。

 

區別

1     在用拉鍊法構造的散列表中,刪除結點的操作易於實現。只要簡單地刪去鏈表上相應的結點即可而對開放地址法構造的散列表,刪除結點不能簡單地將被刪結點的空間置爲空,否則將截斷在它之後填人散列表的同義詞結點的查找路徑。這是因爲各種開放地址法中,空地址單元(即開放地址)都是查找失敗的條件。因此在用開放地址法處理衝突的散列表上執行刪除操作,只能在被刪結點上做刪除標記,而不能真正刪除結點。 

 

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

 

3 開放地址法:容易產生堆積問題;不適於大規模的數據存儲;散列函數的設計對衝突會有很大的影響;插入時可能會出現多次衝突的現象,刪除的元素是多個衝突元素中的一個,需要對後面的元素作處理,實現較複雜;結點規模很大時會浪費很多空間;

 

4 .鏈地址法:處理衝突簡單,且無堆積現象,平均查找長度短;鏈表中的結點是動態申請的,適合構造表不能確定長度的情況;相對而言,拉鍊法的指針域可以忽略不計,因此較開放地址法更加節省空間。插入結點應該在鏈首,刪除結點比較方便,只需調整指針而不需要對其他衝突元素作調整。

 

拉鍊法的優點

 

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

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

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

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

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

 

拉鍊法的缺點

 

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

使用例子:

HashMap

二、開發地址法

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

參考地址

https://blog.csdn.net/qq_30091945/article/details/78044445?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

 

https://blog.csdn.net/cy_cai/article/details/53939174?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

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