hash,一般翻譯做「雜湊」,也有直接音譯為「雜湊」的,就是把任意長度的輸入,通過雜湊演算法,變換成固定長度的輸出,該輸出就是雜湊值。這種轉換是一種壓縮對映,也就是,雜湊值的空間通常遠小於輸入的空間,不同的輸入可能會雜湊成相同的輸出,所以不可能從雜湊值來唯一的確定輸入值。簡單的說就是一種將任意長度的訊息壓縮到某一固定長度的訊息摘要的函式。 碰撞
兩個不同的輸入值,根據同一雜湊函式計算出的雜湊值相同的現象叫做碰撞。
壓縮對映
設(x, ρ)為距離空間,t是x到x中的對映,如果存在數a(0例子
舉個簡單的例子,新華字典,我們查字典的時候,如果按照拼音去查詢(當然按照偏旁部首去查詢也是一樣),比如查詢「位」,按照拼音表,w開頭的拼音
按照步驟來,應該首先去查w開頭的拼音,然後去查詢wei的位置,然後在找到「位」,這個過程就是鍵碼對映,在wei鍵值下有很多字,這些字儲存的時候產生了「碰撞」, 在公式裡面,就是通過key去查詢f(key)。其中,wei就是關鍵字(key),f()就是字典索引,也就是雜湊函式,查到的頁碼就是雜湊值。
剛剛查字的時候,發現wei下有很多字,問題就來了,我們要查的是「位」,而不是「未「,但是他們的拼音是一樣的。也就是通過關鍵字」位「和關鍵字」未「可以對映到一樣的字典頁碼的位置,這就是雜湊衝突(也叫雜湊碰撞),在公式上表達就是key1≠key2,但f(key1)=f(key2)。衝突會給查詢帶來麻煩,你想想,你本來查詢的是「位」,但是卻找到「未」字,你又得向後翻一兩頁,在計算機裡面也是一樣道理的。
但雜湊衝突是無可避免的,為什麼這麼說呢,因為你如果要完全避開這種情況,你只能每個字典去新開乙個頁,然後每個字在索引裡面都有對應的頁碼,這就可以避免衝突。但是會導致空間增大(每個字都有一頁)。
既然無法避免,就只能儘量減少衝突帶來的損失,而乙個好的雜湊函式需要有以下特點:
盡量使關鍵字對應的記錄均勻分配在雜湊表裡面(比如說某廠商賣30棟房子,均勻劃分abc3個區域,如果你劃分a區域1個房子,b區域1個房子,c區域28個房子,有人來查詢c區域的某個房子最壞的情況就是要找28次)。
關鍵字極小的變化可以引起雜湊值極大的變化。
hash函式
雜湊函式能使對乙個資料序列的訪問過程更加迅速有效,通過雜湊函式,資料元素將被更快地定位。常用hash函式有:
直接定址法。取關鍵字或關鍵字的某個線性函式值為雜湊位址。即h(key)=key或h(key) = a·key + b,其中a和b為常數(這種雜湊函式叫做自身函式)
數字分析法。分析一組資料,比如一組員工的出生年月日,這時我們發現出生年月日的前幾位數字大體相同,這樣的話,出現衝突的機率就會很大,但是我們發現年月日的後幾位表示月份和具體日期的數字差別很大,如果用後面的數字來構成雜湊位址,則衝突的機率會明顯降低。因此數字分析法就是找出數字的規律,盡可能利用這些資料來構造衝突機率較低的雜湊位址。
平方取中法。取關鍵字平方後的中間幾位作為雜湊位址。
摺疊法。將關鍵字分割成位數相同的幾部分,最後一部分位數可以不同,然後取這幾部分的疊加和(去除進製)作為雜湊位址。
隨機數法。選擇一隨機函式,取關鍵字作為隨機函式的種子生成隨機值作為雜湊位址,通常用於關鍵字長度不同的場合。
除留餘數法。取關鍵字被某個不大於雜湊表表長m的數p除后所得的餘數為雜湊位址。即 h(key) = key mod p,p<=m。不僅可以對關鍵字直接取模,也可在摺疊、平方取中等運算之後取模。對p的選擇很重要,一般取素數或m,若p選的不好,容易產生碰撞。
time33演算法
這是乙個對字串進行雜湊的函式,現在幾乎所有流行的hashmap都採用了djb hash function,俗稱「times33」演算法。times33的演算法很簡單,就是對字串進行逐個字元遍歷,不斷的乘33,然後把數值相加即可。
核心的演算法就是如下:
unsigned long hash(const char* key){
unsigned long hash=0;
for(int i=0;i處理衝突方法
開放定址法;hi=(h(key) + di) mod m,i=1,2,…,k(k<=m-1),其中h(key)為雜湊函式,m為雜湊表長,di為增量序列,可有下列三種取法:
di=1,2,3,…,m-1,稱線性探測再雜湊;
di=12,-12,22,-22,32,…,±k2,(k<=m/2)稱二次探測再雜湊;
di=偽隨機數序列,稱偽隨機探測再雜湊。
再雜湊法:hi=rhi(key),i=1,2,…,k rhi均是不同的雜湊函式,即在同義詞產生位址衝突時計算另乙個雜湊函式位址,直到衝突不再發生,這種方法不易產生「聚集」,但增加了計算時間。
鏈位址法(拉鍊法)
建立乙個公共溢位區
最常用的就是開發定址法和鏈位址法。
開放定址法
為了使用開放定址法插入乙個元素,需要連續的檢查雜湊表,直到找到乙個新的空槽來放置帶插入的元素為止。檢查的順序不一定是0,1,2,…,m-1的這種順序,而是要依賴待插入的關鍵字key,為了確定探查哪些槽,我們將雜湊函式加以擴充,使之包含探查號作為第二個輸入引數,
下圖演示的是線性探測解決衝突的方法:
二次探測和偽隨機數法和線性探測的模式相同,只是在衝突後,選取平方數和隨機數進行探測
鏈位址法
上面所說的開發定址法的原理是遇到衝突的時候查詢順著原來雜湊位址查詢下乙個空閒位址然後插入,但是也有乙個問題就是如果空間不足,那他無法處理衝突也無法插入資料,因此需要裝填因子(插入資料/空間)<=1。
開放定址法的所有元素都存在於雜湊表之內,每乙個表項要麼存在元素,要麼就為空,當發生對映值衝突的時候我們可以探查新的位置。最好的探查方法是雙重雜湊,因為雙重雜湊產生的探查序列足夠隨機,不像線性探查和二次探查哪樣存在較為嚴重的群集現象。
雜湊表的查詢過程基本上和造表過程相同。一些關鍵碼可通過雜湊函式轉換的位址直接找到,另一些關鍵碼在雜湊函式得到的位址上產生了衝突,需要按處理衝突的方法進行查詢。在介紹的三種處理衝突的方法中,產生衝突後的查詢仍然是給定值與關鍵碼進行比較的過程。所以,對雜湊表查詢效率的量度,依然用平均查詢長度來衡量。
查詢過程中,關鍵碼的比較次數,取決於產生衝突的多少,產生的衝突少,查詢效率就高,產生的衝突多,查詢效率就低。因此,影響產生衝突多少的因素,也就是影響查詢效率的因素。影響產生衝突多少有以下三個因素:
雜湊函式是否均勻;
處理衝突的方法;
雜湊表的裝填因子。
雜湊表的裝填因子定義為:α= 填入表中的元素個數/雜湊表的長度
α是雜湊表裝滿程度的標誌因子。由於表長是定值,α與「填入表中的元素個數」成正比,所以,α越大,填入表中的元素較多,產生衝突的可能性就越大;α越小,填入表中的元素較少,產生衝突的可能性就越小。
實際上,雜湊表的平均查詢長度是裝填因子α的函式,只是不同處理衝突的方法有不同的函式。
由於雜湊表高效的特性,查詢或者插入的情況在大多數情況下可以達到o(1),時間主要花在計算hash上,當然也有最壞的情況就是hash值全都對映到同乙個位址上,這樣雜湊表就會退化成煉表,查詢的時間複雜度變成o(n),但是這種情況比較少,只要不要把hash計算的公式外漏出去並且有人故意攻擊(用興趣的人可以搜一下基於雜湊衝突的拒絕服務攻擊),一般也不會出現這種情況。
如圖所示,雜湊衝突攻擊導致退化成煉表
演算法基礎 Hash演算法
hash,一般翻譯做 雜湊 也有直接音譯為 雜湊 的,就是把任意長度的輸入,通過雜湊演算法,變換成固定長度的輸出,該輸出就是雜湊值。這種轉換是一種壓縮對映,也就是,雜湊值的空間通常遠小於輸入的空間,不同的輸入可能會雜湊成相同的輸出,所以不可能從雜湊值來唯一的確定輸入值。簡單的說就是一種將任意長度的訊...
hash表 hash演算法
概念 雜湊表 hash table。也叫雜湊表 是依據關鍵碼值 key value 而直接進行訪問的 資料結構。也就是說,它通過把關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。給定表m,存在函式f key 對隨意給定的keyword值ke...
Hash演算法與Hash碰撞
什麼是hash演算法。雜湊函式 英語 hash function 又稱雜湊演算法 雜湊函式,是一種從任何一種資料中建立小的數字 指紋 的方法。雜湊函式把訊息或資料壓縮成摘要,使得資料量變小,將資料的格式固定下來。該函式將資料打亂混合,重新建立乙個叫做雜湊值 hash values,hash code...