1. 程式人生 > >雜湊表全解

雜湊表全解

雜湊表定義

雜湊表(Hash table),是根據關鍵碼值(Key - value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。

HashTable(key,value)就是把key通過一個固定的演算法即雜湊函式(雜湊函式)轉換成一個整型數字,然後就將數字對陣列的長度取餘,把這個結果值作為陣列的下標,然後將value存在以該數字為下標的陣列中。而用雜湊表查詢時,可以用雜湊函式把key轉化陣列下標,並且直接定位到該空間獲取value,進行資料定位。

雜湊表的特點:

陣列的特點:定址容易,插入和刪除困難(需要移動資料)

連結串列的特點:定址困難(要遍歷),插入和刪除容易

雜湊表的特點:雜湊表有不同的實現方法,其中一種最常用的拉鍊法(連結串列的陣列),它結合了兩者的特性,定址容易,插入和刪除也容易。

拉鍊法:左側明顯是一個數組,陣列的每一個成員都包括一個指標,指向一個連結串列的投頭,這個連結串列也可以是空,也有可能有元素。我們根據元素的一些特徵把元素分配到不同的連結串列中去,也是根據這些特徵,找到正確的連結串列,再從連結串列中找出這個元素。

雜湊表的應用:

  1、主要用於資訊保安領域中加密演算法,它能把一些不同長度的資訊轉化成雜亂的128位的編碼,即雜湊值。Hash就是找到一種資料內容和資料存放地址之間的對映關係。

  2、用於高效率查詢,之前用的是二分法查詢,現在有了雜湊表,當我們知道了key值以後,就可以直接通過雜湊演算法計算這個元素在陣列中的位置,而不需要一個一個的比對查詢。

  3、雜湊表在海量資料處理中有廣泛的應用。

雜湊法:

元素特徵轉變為陣列下標的方法就是雜湊法。雜湊法當然不止一種,下面列出三種比較常用的:
1,除法雜湊法 最直觀的一種,上圖使用的就是這種雜湊法,公式:   index = value % 16 學過彙編的都知道,求模數其實是通過一個除法運算得到的,所以叫“除法雜湊法”。
2,平方雜湊法 求index是非常頻繁的操作,而乘法的運算要比除法來得省時(對現在的CPU來說,估計我們感覺不出來),所以我們考慮把除法換成乘法和一個位移操作。公式:       index = (value * value) >> 28   (右移,除以2^28。記法:左移變大,是乘。右移變小,是除。)如果數值分配比較均勻的話這種方法能得到不錯的結果,但我上面畫的那個圖的各個元素的值算出來的index都是0——非常失敗。也許你還有個問題,value如果很大,value * value不會溢位嗎?答案是會的,但我們這個乘法不關心溢位,因為我們根本不是為了獲取相乘結果,而是為了獲取index。
3,斐波那契(Fibonacci)雜湊法
平方雜湊法的缺點是顯而易見的,所以我們能不能找出一個理想的乘數,而不是拿value本身當作乘數呢?答案是肯定的。
1,對於16位整數而言,這個乘數是40503 2,對於32位整數而言,這個乘數是2654435769 3,對於64位整數而言,這個乘數是11400714819323198485
    這幾個“理想乘數”是如何得出來的呢?這跟一個法則有關,叫黃金分割法則,而描述黃金分割法則的最經典表示式無疑就是著名的斐波那契數列,即如此形式的序列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377, 610,
 987, 1597, 2584, 4181, 6765, 10946,…。另外,斐波那契數列的值和太陽系八大行星的軌道半徑的比例出奇吻合。
    對我們常見的32位整數而言,公式:             index = (value * 2654435769) >> 28
    如果用這種斐波那契雜湊法的話,那上面的圖就變成這樣了:

適用範圍    快速查詢,刪除的基本資料結構,通常需要總資料量可以放入記憶體。
基本原理及要點    hash函式選擇,針對字串,整數,排列,具體相應的hash方法。 碰撞處理,一種是open hashing,也稱為拉鍊法;另一種就是closed hashing,也稱開地址法,opened addressing。
 

雜湊表的優缺點:

  優點: 不論雜湊表中有多少資料,查詢、插入、刪除(有時包括刪除)只需要接近常量的時間即0(1)的時間級。實際上,這隻需要幾條機器指令。雜湊表運算得非常快,在計算機程式中,如果需要在一秒種內查詢上千條記錄通常使用雜湊表(例如拼寫檢查器)雜湊表的速度明顯比樹快,樹的操作通常需要O(N)的時間級。雜湊表不僅速度快,程式設計實現也相對容易。
如果不需要有序遍歷資料,並且可以提前預測資料量的大小。那麼雜湊表在速度和易用性方面是無與倫比的。

  缺點:

  (1)它是基於陣列的,陣列建立後難於擴充套件,某些雜湊表被基本填滿時,效能下降得非常嚴重,所以程式設計師必須要清楚表中將要儲存多少資料(或者準備好定期地把資料轉移到更大的雜湊表中,這是個費時的過程)。

  (2)一個關鍵字可能對應多個雜湊地址;需要查詢一個範圍時,效果不好。

        雜湊衝突:不同的關鍵字經過雜湊函式的計算得到了相同的雜湊地址。

         好的雜湊函式=計算簡單+分佈均勻(計算得到的雜湊地址分佈均勻)

雜湊衝突的解決方案:


1、緩衝區法:建立一個緩衝區,把凡是拼音重複的人放到緩衝區中。當我通過名字查詢人時,發現找的不對,就在緩衝區裡找。

2、開放地址法:

(1)線性探測法:

(2)二次探測法:

 
 
問題例項(海量資料處理)     我們知道hash 表在海量資料處理中有著廣泛的應用,下面,請看另一道百度面試題:題目:海量日誌資料,提取出某日訪問百度次數最多的那個IP。方案:IP的數目還是有限的,最多2^32個,所以可以考慮使用hash將ip直接存入記憶體,然後進行統計。