C#與資料結構--雜湊表(2)?

其中,m為雜湊表長。由此可知,雙重雜湊法探測下一個開放地址的公式為:

  (h1(key)
+ i * h2(key)) % m     (1≤i≤m-1)

  定義h2的方法較多,但無採用什麼方法都必須使h2(key)的值和m互素(又稱互質,表示兩數的最大公約數為1,或者說是兩數沒有共同的因子,1除外)才能使發生衝突的同義詞地址均勻地分佈在整個雜湊表中,否則可能造成同義詞地址的迴圈計算。若m為素數,則h2取1至m-1之間的任何數均與m互素,因此可以簡單地將h2定義為:

  h2(key)
= key % (m - 2) + 1

  8.4
剖析System.Collections.Hashtable

  萬物之母object類中定義了一個GetHashCode()方法,這個方法預設的實現是返回一個唯一的整數值以保證在object的生命期中不被修改。既然每種型別都是直接或間接從object派生的,因此所有物件都可以訪問該方法。自然,字串或其他型別都能以唯一的數字值來表示。也就是說,GetHashCode()方法使得所有物件的雜湊函式構造方法都趨於統一。當然,由於GetHashCode()方法是一個虛方法,你也可以通過重寫這個方法來構造自己的雜湊函式。

  8.4.1 
Hashtable的實現原理

  Hashtable使用了閉雜湊法來解決衝突,它通過一個結構體bucket來表示雜湊表中的單個元素,這個結構體中有三個成員:

  (1)      
key :表示鍵,即雜湊表中的關鍵字。

  (2)      
val :表示值,即跟關鍵字所對應值。

  (3)      
hash_coll :它是一個int型別,用於表示鍵所對應的雜湊碼。

  int型別佔據32個位的儲存空間,它的最高位是符號位,為“0”時,表示這是一個正整數;為“1”時表示負整數。hash_coll使用最高位表示當前位置是否發生衝突,為“0”時,也就是為正數時,表示未發生衝突;為“1”時,表示當前位置存在衝突。之所以專門使用一個位用於存放雜湊碼並標註是否發生衝突,主要是為了提高雜湊表的執行效率。關於這一點,稍後會提到。

Hashtable解決衝突使用了雙重雜湊法,但又跟前面所講的雙重雜湊法稍有不同。它探測地址的方法如下:

  h(key,
i) = h1(key) + i * h2(key)

  其中雜湊函式h1和h2的公式如下:

  h1(key)
= key.GetHashCode()

  h2(key)
= 1 + (((h1(key) >> 5) + 1) % (hashsize - 1))

  由於使用了二度雜湊,最終的h(key,
i)的值有可能會大於hashsize,所以需要對h(key, i)進行模運算,最終計算的雜湊地址為:

  雜湊地址
= h(key, i) % hashsize

  【注意】:bucket結構體的hash_coll欄位所儲存的是h(key,
i)的值而不是雜湊地址。

 雜湊表的所有元素存放於一個名稱為buckets(又稱為資料桶)
的bucket陣列之中,下面演示一個雜湊表的資料的插入和刪除過程,其中資料元素使用(鍵,值,雜湊碼)來表示。注意,本例假設Hashtable的長度為11,即hashsize
= 11,這裡只顯示其中的前5個元素。

  (1)插入元素(k1,v1,1)和(k2,v2,2)。

  由於插入的兩個元素不存在衝突,所以直接使用h1(key)
% hashsize的值做為其雜湊碼而忽略了h2(key)。其效果如圖8.6所示。

  (2)插入元素(k3,v3,12)

  
新插入的元素的雜湊碼為12,由於雜湊表長為11,12 % 11 =
1,所以新元素應該插入到索引1處,但由於索引1處已經被k1佔據,所以需要使用h2(key)重新計算雜湊碼。

h2(key)
= 1 + (((h1(key) >> 5) + 1) % (hashsize - 1))

  h2(key)
= 1 + ((12 >> 5) + 1) % (11 - 1)) = 2

相關問題答案