JAVA資料結構之雜湊表

qq_42606051發表於2018-08-15

Hash表簡介: 

  Hash表是基於陣列的,優點是提供快速的插入和查詢的操作,程式設計實現相對容易,缺點是一旦建立就不好擴充套件,當hash表被基本填滿的時候,效能下降非常嚴重(發生聚集引起的效能的下降),而且沒有簡便方法以任何一種順序來遍歷表中的資料項,若需要,則要考慮其他的資料結構(選擇hash表儲存資料一般是不需要有序遍歷資料,可以提前預測資料量的大小)

  Hash化:在hash表中我們一般通過hash函式將資料的關鍵字轉換成為陣列的下標(若關鍵字可以直接作為陣列的下標則不需要hash函式轉換)。現在我們假設要在記憶體中儲存50000個單詞,此時關鍵字單詞不能直接作為我們的陣列的下標,所以我們就需要將其用我們的hash函式轉換一下得到我們的陣列的下標,這裡我們用1-26代表我們真的字母a-z空格我們用0代表,接下來我們要探討如何將代表單個字母的數字組合成代表整個單詞的數字呢,有兩種具有代表性的方法,假設我們約定單詞由十個字母組成,

  第一種是把每個字母對應的數字相加得到陣列的下標:

  空位是0那麼第一個單詞a就是0+0+0+0+0+0+0+0+0+1 = 1,最後一個單詞是zzzzzzzzzz對應的陣列下標是26+26+26+26+26+26+26+26+26+26 = 260,這裡我們可以明顯地看到,我們的儲存陣列的大小是260,明顯不夠我們儲存50000個單詞,所以這裡的每一個陣列項都要包含一個陣列或連結串列,這樣就嚴重降低了存取的速度。

  第二種是使用冪的連乘:

  我們將每個字母對應的數字乘以適當的27的冪(由於包括空格有27個字元),在字母的第一位乘以0次冪第二位乘以1次冪以此類推,然後將每一個結果相加得到我們最終的陣列的下標,例如我們將cats依此轉換3*273+1*272+20*271+19*270 =60337這樣可以為每一個單詞建立獨一無二的整數但是此時的問題是單詞zzzzzzzzzz計算出來的數值變得非常大279=7000000000000結果非常巨大其中大多數結果都是空的

  對於英語詞典我們儲存50000個單詞大約需要多餘一倍的空間來容納這些單詞(由於當hash填滿的時候對其效能影響很大),所以需要容量100000的陣列,我們需要將0到超過7000000000000的範圍,壓縮為0-100000的範圍,使用上面通過計算得到的數字(這個數字可能超出變數範圍)來對我們的壓縮範圍取餘可以得到我們最終壓縮後的數字,將這樣巨大的數字空間壓縮成較小的數字空間,由於不能保證每個單詞都對映到陣列的空白單元,這時候就會發生衝突,解決這樣衝突我們一般使用開放地址法和鏈地址法。

開放地址法:通過系統的方法找到系統的空位(三種:線性探測、二次探測、再雜湊法),並將插入的單詞填入,而不再使用用hash函式得到數字作為陣列的下標。

  • 線性探測假若當前要插入的位置已經被佔用了之後,沿陣列下標遞增方向查詢,直到找到空位為止
  • 二次探測二次探測和線性探測的區別在於二次探測的步長是,若計算的原始下標是x則二次探測的過程是x+12,x+22,x+32,x+42,x+52隨著探測次數的增加,探測的步長是探測次數的二次方(因此名為二次探測)。二次探測會產生二次聚集:即當插入的幾個數經過hash後的下標相同的話,那麼這一串數字插入的探測步長會增加很快
  • hash法:為了消除原始聚集和二次聚集,把關鍵字用不同的hash函式再做一遍hash化,用過這個結果作為探測的步長,這樣對於特定的關鍵字在整個探測中步長不變,但是不同的關鍵字會使用不同的步長。stepSize = constant - (key % constant) 這個hash函式求步長比較實用,constant是小於陣列容量的質數。(注意:第二個hash函式必須和第一個hash函式不同,步長hash函式輸出的結果值不能為0)

下面給出再hash的JAVA程式碼

 再雜湊法JAVA程式碼

 鏈地址法  :建立一個存放單詞連結串列的陣列,陣列內不直接儲存單詞,而是儲存單詞的連結串列或陣列。發生衝突的時候,資料項直接接到這個陣列下標所指的連結串列中即可。

  優勢:填入過程允許重複,所有關鍵值相同的項放在同一連結串列中,找到所有項就需要查詢整個是連結串列,稍微有點影響效能。刪除只需要找到正確的連結串列,從連結串列中刪除對應的資料即可。表容量是質數的要求不像在二次探測和再hash法中那麼重要,由於沒有探測的操作,所以無需擔心容量被步長整除,從而陷入無限迴圈中。接下來給出鏈地址法的JAVA程式碼:

 鏈地址法的JAVA程式碼

 ps:桶:類似於鏈地址法,只是將連結串列換為陣列這樣的陣列有時稱為桶,但是桶的容量不好選擇。

Hash化的效率: 

  下圖顯示了不同的hash方法的效率情況

 

  從上圖我們可以看到開放地址法隨著裝填因子變大,比較次數後期會急劇變大,所以使用開放地址法的時候儘量保持裝填因子不能超過2/3,二次探測和再hash法的效能相當,他們都要比線性探測要好。當裝填因子為0.5的時候成功和不成功的查詢需要平均2次比較,當裝填因子為0.8的時候分別需要2.9和5.0次查詢,所以對於較高的裝填因子,可以選擇二次探測和再hash法。鏈地址法的效率,所有的操作都需要1+nComps的時間,nComps表示關鍵字的比較次數,和裝填因子有關,裝填因子的大小影響每一個連結串列的平均長度,從而會影響每個關鍵字在連結串列中的比較次數,從而影響效率。

  如果在hash表建立的時候,填入的項數未知,鏈地址法好於開放地址法,當裝填因子變大的時候開放地址法的效率下降很快,而鏈地址法效率是線性地下降。兩種都可選的時候也推薦選擇鏈地址法,雖然要使用到連結串列類,但是當要增加比預期更多的資料的時候效能不會快速的下降

以上就是hash表資料結構的所有內容

來源:https://www.cnblogs.com/zhoukebo/p/9473364.html

鄭州治療婦科疾病醫院

鄭州人流醫院

鄭州婦科醫院那個好

鄭州同濟男子醫院

相關文章