經典資料結構 Hash演算法

2021-06-10 11:04:29 字數 2654 閱讀 6659

**:

什麼是雜湊表?

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

雜湊表的做法其實很簡單,就是把key通過乙個固定的演算法函式既所謂的雜湊函式轉換成乙個整型數字,然後就將該數字對陣列長度進行取餘,取餘結果就當作陣列的下標,將value儲存在以該數字為下標的陣列空間裡。

而當使用雜湊表進行查詢的時候,就是再次使用雜湊函式將key轉換為對應的陣列下標,並定位到該空間獲取value,如此一來,就可以充分利用到陣列的定位效能進行資料定位

什麼是hash

hash,一般翻譯做「雜湊」,也有直接音譯為「雜湊」的,就是把任意長度的輸入(又叫做預對映, pre-image),通過雜湊演算法,變換成固定長度的輸出,該輸出就是雜湊值。這種轉換是一種壓縮對映,也就是,雜湊值的空間通常遠小於輸入的空間,不同的輸入可能會雜湊成相同的輸出,而不可能從雜湊值來唯一的確定輸入值。簡單的說就是一種將任意長度的訊息壓縮到某一固定長度的訊息摘要的函式。

hash主要用於資訊保安領域中加密演算法,它把一些不同長度的資訊轉化成雜亂的128位的編碼,這些編碼值叫做hash值. 也可以說,hash就是找到一種資料內容和資料存放位址之間的對映關係。

陣列的特點是:定址容易,插入和刪除困難;而鍊錶的特點是:定址困難,插入和刪除容易。那麼我們能不能綜合兩者的特性,做出一種定址容易,插入刪除也容易的資料結構?答案是肯定的,這就是我們要提起的雜湊表,雜湊表有多種不同的實現方法,我接下來解釋的是最常用的一種方法——拉鍊法,我們可以理解為「鍊錶的陣列」,如圖:

左邊很明顯是個陣列,陣列的每個成員包括乙個指標,指向乙個鍊錶的頭,當然這個鍊錶可能為空,也可能元素很多。我們根據元素的一些特徵把元素分配到不同的鍊錶中去,也是根據這些特徵,找到正確的鍊錶,再從鍊錶中找出這個元素。

元素特徵轉變為陣列下標的方法就是雜湊法。

雜湊法當然不止一種,下面列出三種比較常用的:

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。

擴充套件d-left hashing中的d是多個的意思,我們先簡化這個問題,看一看2-left hashing。2-left hashing指的是將乙個雜湊表分成長度相等的兩半,分別叫做t1和t2,給t1和t2分別配備乙個雜湊函式,h1和h2。在儲存乙個新的key時,同 時用兩個雜湊函式進行計算,得出兩個位址h1[key]和h2[key]。這時需要檢查t1中的h1[key]位置和t2中的h2[key]位置,哪乙個 位置已經儲存的(有碰撞的)key比較多,然後將新key儲存在負載少的位置。如果兩邊一樣多,比如兩個位置都為空或者都儲存了乙個key,就把新key 儲存在左邊的t1子表中,2-left也由此而來。在查詢乙個key時,必須進行兩次hash,同時查詢兩個位置。

資料結構經典演算法

例如 4和3只出現過一次,請找出出現過一次的數。首先想到的 應該是上乙個提到的遍歷兩次取出沒有找到的相同的數字,如下 public static list findonlynum int array if j array.length if array i array j if j array.le...

資料結構 hash

雜湊表 hash table,也叫雜湊表 是根據鍵 key 而直接訪問在記憶體儲存位置的資料結構。分為兩個步驟 hash函式 通過乙個關於鍵值的hash函式,得到所查詢的資料對映到表中乙個位置。訪問資料 不同的key 經過hash函式 可能計算得到相同的輸出。此時叫做衝突,衝突的資料又成乙個表。一般...

資料結構與演算法篇 hash

python中dict結構用雜湊表構建,採用開放定址法解決雜湊衝突 1 雜湊函式構造方法 自己選擇某種規則,避免衝突 直接定址法 數字分析法 平方取中法 摺疊法 除留餘數法 除數為質數 2 解決衝突方法 待插入的元素按雜湊函式計算得到的位址已經被占用 開放定址法 線性探測再雜湊,位址不斷加1,2,3...