記錄的儲存位置=f(關鍵字)
這裡的對應關係f稱為雜湊函式,又稱為雜湊(hash函式),採用雜湊技術將記錄儲存在一塊連續的儲存空間中,這塊連續儲存空間稱為雜湊表或雜湊表(hash table)。
雜湊表hashtable(key,value) 就是把key通過乙個固定的演算法函式既所謂的雜湊函式轉換成乙個整型數字,然後就將該數字對陣列長度進行取餘,取餘結果就當作陣列的下標,將value儲存在以該數字為下標的陣列空間裡。(或者:把任意長度的輸入(又叫做預對映, pre-image),通過雜湊演算法,變換成固定長度的輸出,該輸出就是雜湊值。這種轉換是一種壓縮對映,也就是,雜湊值的空間通常遠小於輸入的空間,不同的輸入可能會雜湊成相同的輸出,而不可能從雜湊值來唯一的確定輸入值。簡單的說就是一種將任意長度的訊息壓縮到某一固定長度的訊息摘要的函式。)
而當使用雜湊表進行查詢的時候,就是再次使用雜湊函式將key轉換為對應的陣列下標,並定位到該空間獲取value,如此一來,就可以充分利用到陣列的定位效能進行資料定位。
陣列的特點是:定址容易,插入和刪除困難;
而鍊錶的特點是:定址困難,插入和刪除容易。
那麼我們能不能綜合兩者的特性,做出一種定址容易,插入刪除也容易的資料結構?答案是肯定的,這就是我們要提起的雜湊表,雜湊表有多種不同的實現方法,我接下來解釋的是最常用的一種方法——拉鍊法,我們可以理解為「鍊錶的陣列」,如圖:
左邊很明顯是個陣列,陣列的每個成員包括乙個指標,指向乙個鍊錶的頭,當然這個鍊錶可能為空,也可能元素很多。我們根據元素的一些特徵把元素分配到不同的鍊錶中去,也是根據這些特徵,找到正確的鍊錶,再從鍊錶中找出這個元素。
舉乙個例子,假如我的陣列a中,第i個元素裡面裝的key就是i,那麼數字3肯定是在第3個位置,數字10肯定是在第10個位置。雜湊表就是利用利用這種基本的思想,建立乙個從key到位置的函式,然後進行直接計算查詢。
hash table的查詢速度非常的快,幾乎是o(1)的時間複雜度。
hash就是找到一種資料內容和資料存放位址之間的對映關係。
雜湊法:元素特徵轉變為陣列下標的方法。
我想大家都在想乙個很嚴重的問題:「如果兩個字串在雜湊表中對應的位置相同怎麼辦?」,畢竟乙個陣列容量是有限的,這種可能性很大。解決該問題的方法很多,我首先想到的就是用「鍊錶」。我遇到的很多演算法都可以轉化成鍊錶來解決,只要在雜湊表的每個入口掛乙個鍊錶,儲存所有對應的字串就ok了。
雜湊表的查詢步驟
當儲存記錄時,通過雜湊函式計算出記錄的雜湊位址
當查詢記錄時,我們通過同樣的是雜湊函式計算記錄的雜湊位址,並按此雜湊位址訪問該記錄
關鍵字——雜湊函式(雜湊函式)——雜湊位址
優點:一對一的查詢效率很高;
好的雜湊函式=計算簡單+分布均勻(計算得到的雜湊位址分布均勻)
雜湊表是種資料結構,它可以提供快速的插入操作和查詢操作。
優點:不論雜湊表中有多少資料,查詢、插入、刪除(有時包括刪除)只需要接近常量的時間即0(1)的時間級。實際上,這只需要幾條機器指令。
雜湊表運算得非常快,在電腦程式中,如果需要在一秒種內查詢上千條記錄通常使用雜湊表(例如拼寫檢查器)雜湊表的速度明顯比樹快,樹的操作通常需要o(n)的時間級。雜湊表不僅速度快,程式設計實現也相對容易。
如果不需要有序遍歷資料,並且可以提前**資料量的大小。那麼雜湊表在速度和易用性方面是無與倫比的。
缺點:它是基於陣列的,陣列建立後難於擴充套件,某些雜湊表被基本填滿時,效能下降得非常嚴重,所以程式設計師必須要清楚表中將要儲存多少資料(或者準備好定期地把資料轉移到更大的雜湊表中,這是個費時的過程)。
元素特徵轉變為陣列下標的方法就是雜湊法。雜湊法當然不止一種,下面列出三種比較常用的:
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。
雜湊衝突的解決方案:
1.建立乙個緩衝區,把凡是拼音重複的人放到緩衝區中。當我通過名字查詢人時,發現找的不對,就在緩衝區裡找。
2.進行再探測。就是在其他地方查詢。探測的方法也可以有很多種。
(1)在找到查詢位置的index的index-1,index+1位置查詢,index-2,index+2查詢,依次類推。這種方法稱為線性再探測。
(2)在查詢位置index周圍隨機的查詢。稱為隨機在探測。
(3)再雜湊。就是當衝突時,採用另外一種對映方式來查詢。
這個程式中是通過取模來模擬查詢到重複元素的過程。對待重複元素的方法就是再雜湊:對當前key的位置+7。最後,可以通過全域性變數來判斷需要查詢多少次。我這裡通過依次查詢26個英文本母的小寫計算的出了總的查詢次數。顯然,當總的查詢次數/查詢的總元素數越接近1時,雜湊表更接近於一一對映的函式,查詢的效率更高。
擴充套件
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,同時查詢兩個位置。
問題例項(海量資料處理)
資料結構 雜湊表(雜湊表)hash table
hash table 在計算機中,雜湊表 是 一種實現了關聯陣列 抽象資料型別的資料結構,這種資料結構可以對映 鍵 key 和 值 value 補充 關聯陣列 在電腦科學中,乙個關聯陣列 associative array 對映 map 符號表 symbol table 或者是字典 dictiona...
資料結構 雜湊表查詢(雜湊表)
對於查詢,有順序表直接遍歷,有折半查詢直到查詢成功。但是這都需要不斷的比較,每一次查詢都需要重新遍歷,所以當資料龐大時是非常耗時的。雜湊表是一種可以避免多次比較,直接通過關鍵字就可以得到要查詢的記錄記憶體儲存位置。例如就像是乙個函式,每乙個自變數都對應著乙個函式值,即 這屬於雜湊技術,不需要比較就可...
資料結構 雜湊表1(雜湊表)
雜湊表 雜湊表是一種資料結構,它提供了快速的插入操作和查詢操作,其基於陣列來實現。雜湊化方式 1 直接將關鍵字作為索引。弊端 關鍵字資料型別只能是整形。2 將單詞轉換成索引。將字母轉換成ascii碼,然後進行相加。弊端 會出現不同的字串轉換ascii碼的值和相同。冪的連乘。弊端 通過冪的連乘得到的k...