hash table碰撞處理

有兩種策略來解決hash table的碰撞問題。第一種策略是open addressing,若是數組中當前位置已經被佔用,他會爲當前數據從新選擇一個位置;第二種策略是separate chaining,在數組每個位置安放一個鏈表。 html

1.Open Addressing 算法

若是當前數據所修位置被佔用,該策略會爲數據從新選擇一個位置。這種測略有三種方法可使用: 數組

a.Liner probing 函數

這種方法簡單的以當前位置爲起點,線性搜索空閒位置。若是hash函數選擇了第n個位置給當前數據,可是n位置已經被佔用,該方法將會嘗試n+1,n+2.........,知道找到一個空閒位置,若是到達數組末尾,則從數組頭繼續搜索。這個嘗試不一樣位置的過程叫作probing。 spa

之因此叫作Liner probing,是由於這個過程看起來像線性搜索。 指針

當須要在hash table中搜索數據時候,一樣要是用probing,當經過key來搜索數據,且hash函數獲得的位置是x,若是x位置包含其餘的數據,那麼繼續搜索x+1,x+2,直到搜索到目標元素,或者x+k位置爲空,或者又從新便利到x位置。 htm

Liner probing的問題是clustering(聚合),數據元素成塊狀分佈。若是插入一個映射到x位置的值,可是x被佔用了,插入方法將嘗試x+1。若是下一個元素被映射到x+1,而這個位置被佔用了,那他就得繼續日後嘗試。數據將會彙集成一塊一塊的。在實際應用中,若是插入數據類似,那麼會產生數據聚合,致使搜索和插入數據效率降低。 blog

解決這個問題的方法是move ahead,不只僅是前移一個元素位置。在quadratic probing中,插入方法將嘗試x+1^2,x+2^2,x+3^2.........直到找到空閒位置,在查找時候也要這麼作。 get


b.Quadratic probing hash

Quadratic probing的好處是能夠下降clustering,由於probing的偏移是n^2,而不是1,不會使得數據很接近。可是若是不少數據同時被映射到同一個位置上,那麼這種方法也是於事無補的。當有不少數據被映射到同一個位置時候,他將會嘗試x+1,x+4,x+9...............這將使數據查找變得困難。


c.double hashing

double hashing中,probing的偏移取決於key value本身。當key映射到位置x,而x已經被佔用的時候,則用第二個hash函數對key進行處理獲得y,嘗試x+y,x+2y,x

+3y..........直到找到一個能夠插入的位置。選擇第二個hash函數的目標是:hash函數值永遠大於等於1,對於key的獲得的hash結果和第一個hash函數不一樣。一般,第二個hash函數這麼寫:

probe offset  =  c - key%c,    c是一個小於數組大小的常數


2.Separate chaining

這種方法在數組的每個位置上用一個鏈表

/////////////////////////////////////////////////////////////////////////

動態查找表--哈希表--哈希表衝突的解決

「處理衝突」的含義是:爲產生衝突的關鍵字尋找下一個哈希地址。一般有兩類方法處理衝突:開放定址(Open Addressing)法和拉鍊(Chaining)法。前者是將全部結點均存放在散列表T[0..m-1]中;後者一般是將互爲同義詞的結點鏈成一個單鏈表,而將此鏈表的頭指針放在散列表T[0..m-1]中。

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 )按線性探測再散列和二次探測再散列的方法分別構造哈希表。 

①線性探查法(Linear Probing)
該方法的基本思想是:

     將散列表T[0..m-1]當作是一個循環向量,若初始探查的地址爲d(即h(key)=d),則最長的探查序列爲:
        d,d+l,d+2,…,m-1,0,1,…,d-1
     即:探查時從地址d開始,首先探查T[d],而後依次探查T[d+1],…,直到T[m-1],此後又循環到T[0],T[1],…,直到探查到T[d-1]爲止。

探查過程終止於三種狀況:
     (1)若當前探查的單元爲空,則表示查找失敗(如果插入則將key寫入其中);
     (2)若當前探查的單元中含有key,則查找成功,但對於插入意味着失敗;
     (3)若探查到T[d-1]時仍未發現空單元也未找到key,則不管是查找仍是插入均意味着失敗(此時表滿)。

彙集或堆積現象 
     用線性探查法解決衝突時,當表中i,i+1,…,i+k的位置上已有結點時,一個散列地址爲i,i+1,…,i+k+1的結點都將插入在位置i+k+1上。把這種散列地址不一樣的結點爭奪同一個後繼散列地址的現象稱爲彙集或堆積(Clustering)。這將形成不是同義詞的結點也處在同一個探查序列之中,從而增長了探查序列的長度,即增長了查找時間。若散列函數很差或裝填因子過大,都會使堆積現象加重。

 ②二次探查法(Quadratic Probing)
    二次探查法的探查序列是:
         hi=(h(key)+i*i)%m 0≤i≤m-1 //即di=i2
   即探查序列爲d=h(key),d+12,d+22,…,等。
     該方法的缺陷是不易探查到整個散列空間。

③雙重散列法(Double Hashing)
     該方法是開放定址法中最好的方法之一,它的探查序列是:
       hi=(h(key)+i*h1(key))%m 0≤i≤m-1 //即di=i*h1(key)
     即探查序列爲:
       d=h(key),(d+h1(key))%m,(d+2h1(key))%m,…,等。
   該方法使用了兩個散列函數h(key)和h1(key),故也稱爲雙散列函數探查法。
注意:
     定義h1(key)的方法較多,但不管採用什麼方法定義,都必須使h1(key)的值和m互素,才能使發生衝突的同義詞地址均勻地分佈在整個表中,不然可能形成同義詞地址的循環計算。
  【例】 若m爲素數,則h1(key)取1到m-1之間的任何數均與m互素,所以,咱們能夠簡單地將它定義爲:
               h1(key)=key%(m-2)+1
  【例】對例9.1,咱們可取h(key)=key%13,而h1(key)=key%11+1。
  【例】若m是2的方冪,則h1(key)可取1到m-1之間的任何奇數。

二、拉鍊法
(1)拉鍊法解決衝突的方法
     拉鍊法解決衝突的作法是:將全部關鍵字爲同義詞的結點連接在同一個單鏈表中。若選定的散列表長度爲m,則可將散列表定義爲一個由m個頭指針組成的指針數組T[0..m-1]。凡是散列地址爲i的結點,均插入到以T[i]爲頭指針的單鏈表中。T中各份量的初值均應爲空指針。在拉鍊法中,裝填因子α能夠大於1,但通常均取α≤1。

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

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

三、創建一個公共溢出區

假設哈希函數的值域爲[0,m-1],則設向量HashTable[0..m-1]爲基本表,另外設立存儲空間向量OverTable[0..v]用以存儲發生衝突的記錄。通過以上方法,基本能夠解決掉hash算法衝突的問題。

相關文章
相關標籤/搜索