因為工作原因,看了一下redis的底層實現,發現redis底層使用的哈希算法是murmurhash,第一次聽說這個算法感覺自己對哈希值計算的常用算法了解太少,整理了一下網上講的比較原理性的觀點:
2.基於移位的散列
和加法散列類似,基於移位的散列也要利用字符串數據中的每個元素,但是和加法不同的是,后者更多的而是進行位的移位操作。通常是結合了左移和右移,移的位數的也是一個素數。每個移位過程的結果只是增加了一些積累計算,最后移位的結果作為最終結果。
沒有人可以證明素數和偽隨機數生成器之間的關系,但是目前來說最好的結果使用了素數。偽隨機數生成器現在是一個統計學上的東西,不是一個確定的實體,所以對其的分析只能對整個的結果有一些認識,而不能知道這些結果是怎么產生的。如果能進行更具體的研究,也許我們能更好的理解哪些數值比較有效,為什么素數比其他數更有效,為什么有些素數就不行,如果能用可再現的證明來回答這些問題,那么我們就能設計出更好的偽隨機數生成器,也可能得到更好的哈希函數。
圍繞着哈希函數中的素數的使用的基本的概念是,利用一個素質來改變處理的哈希函數的狀態值,而不是使用其他類型的數。處理這個詞的意思就是對哈希值進行一些簡單的操作,比如乘法和加法。這樣得到的一個新的哈希值一定要在統計學上具有更高的熵,也就是說不能有為偏向。簡單的說,當你用一個素數去乘一堆隨機數的時候,得到的數在bit這個層次上是1的概率應該接近0.5。沒有具體的證明這種不便向的現象只出現在使用素數的情況下,這看上去只是一個自我宣稱的直覺上的理論,並被一些業內人士所遵循。
決定什么是正確的,甚至更好的方法和對散列素數的使用最好的組合仍然是一個很有黑色藝術。沒有單一的方法可以宣稱自己是最終的通用散列函數。最好的一所能做的就是通過試錯演進和獲得適當的散列算法,以滿足其需要的統計分析方法。
位序列發生器是純粹隨機的或者說在某種程度上確定性的,可以按照一定的概率產生某種狀態或相反狀態的比特,這個概率就是位偏向。在純粹隨機的情況下,產生高位或者低位的位偏向應該是50%。
然后在偽隨機產生器中,算法將決定在產生器在最小輸出模塊的位偏向。
假設一個PRNG的產生8位作為其輸出塊。出於某種原因,MSB始終是設置為高,MSB的位偏向將是100%的概率被置高。這一結論是,即使有256個本PRNG的產生可能的值,值小於128將永遠不會產生。為簡單起見,假設其他位正在生成純粹是隨機的,那么有平等的機會,128和255之間的任何值將產生,但是在同一時間,有0%的機會,一個小於128的值會產生。
所有PRNGs,無論是雜湊函數,密碼,msequences或其他任何產生比特流的產生器都會有這樣一個位偏向。大多數PRNGs他們將嘗試收斂位偏向到一個確定值,流密碼就是一個例子,而其他產生器在不確定的位偏向下效果更好。
混合或位序列加擾是一種產生在一個共同的平等流位偏向的方法。雖然我們必須要小心,以確保他們不會混合至發散位偏向。密碼學中的一個混合使用的形式被稱為雪崩,這就是一個位塊使用用另一個塊來替換或置換混合在一起,而另一塊產生與其他快混合的輸出。
正如下圖中顯示的,雪崩過程始於一個或多個二進制數據塊。對數據中的某些位操作(通常是一些輸入敏感位入減少位邏輯)生產的第i層片數據。然后重復這個過程是在第i層數據,以生成一個i+1個層數據,是當前層的位數將小於或等於前層的位數。
這一反復的過程將導致一個依靠之前數據所有位的位。
哈希是一個在現實世界中將數據映射到一個標識符的工具,下面是哈希函數的一些常用領域:
1.字符串哈希
在數據存儲領域,主要是數據的索引和對容器的結構化支持,比如哈希表。
2.加密哈希
用於數據/用戶核查和驗證。一個強大的加密哈希函數很難從結果再得到原始數據。加密哈希函數用於哈希用戶的密碼,用來代替密碼本身存在某個服務器撒很難過。加密哈希函數也被視為不可逆的壓縮功能,能夠代表一個信號標識的大量數據,可以非常有用的判斷當前的數據是否已經被篡改(比如MD5),也可以作為一個數據標志使用,以證明了通過其他手段加密文件的真實性。
3.幾何哈希
這個哈希表用於在計算機視覺領域,為在任意場景分類物體的探測。
哈希值是計算從星座的特性。這通常是由最初定義一個地方的哈希值是為了居住空間中完成- 在這種情況下,散列值是一個多層面的價值,定義的空間正常化。再加上計算的哈希值另一個進程,決定了兩個哈希值之間的距離是必要的過程-一個距離測量是必需的,而不是一個確定性的平等經營者由於對星座的哈希值計算到了可能的差距問題。也因為簡單的歐氏距離度量的本質上是無效的,其結果是自動確定特定空間的距離度量已成為學術界研究的活躍領域處理這類空間的非線性性質。
幾何散列包括各種汽車分類的重新檢測中任意場景的目的,典型的例子。檢測水平可以多種多樣,從剛檢測是否是車輛,到特定型號的車輛,在特定的某個車輛。
隨后的研究工作集中在的散列函數和哈希表以及Mitzenmacher的布隆過濾器等領域。建議對這種結構,在數據被散列熵最實用的用法有助於哈希函數熵,這是理論成果上締結一項最佳的布隆過濾器(一個提供給定一個最低的進一步導致假陽性的可能性表的大小或反之亦然)提供假陽性的概率定義用戶可以建造最多也作為兩種截然不同的兩兩獨立的哈希散列函數已知功能,大大提高了查詢效率的成員。
布隆過濾器通常存在於諸如拼寫檢查器,字符串匹配算法,網絡數據包分析工具和網絡/ Internet緩存的應用程序。
- public long RSHash(String str)
- {
- int b = 378551;
- int a = 63689;
- long hash = 0;
- for(int i = 0; i < str.length(); i++)
- {
- hash = hash * a + str.charAt(i);
- a = a * b;
- }
- return hash;
- }
- public long JSHash(String str)
- {
- long hash = 1315423911;
- for(int i = 0; i < str.length(); i++)
- {
- hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
- }
- return hash;
- }
- public long PJWHash(String str)
- {
- long BitsInUnsignedInt = (long)(4 * 8);
- long ThreeQuarters = (long)((BitsInUnsignedInt * 3) / 4);
- long OneEighth = (long)(BitsInUnsignedInt / 8);
- long HighBits = (long)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
- long hash = 0;
- long test = 0;
- for(int i = 0; i < str.length(); i++)
- {
- hash = (hash << OneEighth) + str.charAt(i);
- if((test = hash & HighBits) != 0)
- {
- hash = (( hash ^ (test >> ThreeQuarters)) & (~HighBits));
- }
- }
- return hash;
- }
- public long ELFHash(String str)
- {
- long hash = 0;
- long x = 0;
- for(int i = 0; i < str.length(); i++)
- {
- hash = (hash << 4) + str.charAt(i);
- if((x = hash & 0xF0000000L) != 0)
- {
- hash ^= (x >> 24);
- }
- hash &= ~x;
- }
- return hash;
- }
- public long BKDRHash(String str)
- {
- long seed = 131; // 31 131 1313 13131 131313 etc..
- long hash = 0;
- for(int i = 0; i < str.length(); i++)
- {
- hash = (hash * seed) + str.charAt(i);
- }
- return hash;
- }
- public long SDBMHash(String str)
- {
- long hash = 0;
- for(int i = 0; i < str.length(); i++)
- {
- hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
- }
- return hash;
- }
- public long DJBHash(String str)
- {
- long hash = 5381;
- for(int i = 0; i < str.length(); i++)
- {
- hash = ((hash << 5) + hash) + str.charAt(i);
- }
- return hash;
- }
- public long DEKHash(String str)
- {
- long hash = str.length();
- for(int i = 0; i < str.length(); i++)
- {
- hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
- }
- return hash;
- }
- public long APHash(String str)
- {
- long hash = 0xAAAAAAAA;
- for(int i = 0; i < str.length(); i++)
- {
- if ((i & 1) == 0)
- {
- hash ^= ((hash << 7) ^ str.charAt(i) * (hash >> 3));
- }
- else
- {
- hash ^= (~((hash << 11) + str.charAt(i) ^ (hash >> 5)));
- }
- }
- return hash;
- }
10, murmurhash
unsigned long long MurmurHash64B ( const void * key, int len, unsigned int seed )
{
const unsigned int m = 0x5bd1e995;
const int r = 24;
unsigned int h1 = seed ^ len;
unsigned int h2 = 0;
const unsigned int * data = (const unsigned int *)key;
while(len >= 8)
{
unsigned int k1 = *data++;
k1 *= m; k1 ^= k1 >> r; k1 *= m;
h1 *= m; h1 ^= k1;
len -= 4;
unsigned int k2 = *data++;
k2 *= m; k2 ^= k2 >> r; k2 *= m;
h2 *= m; h2 ^= k2;
len -= 4;
}
if(len >= 4)
{
unsigned int k1 = *data++;
k1 *= m; k1 ^= k1 >> r; k1 *= m;
h1 *= m; h1 ^= k1;
len -= 4;
}
switch(len)
{
case 3: h2 ^= ((unsigned char*)data)[2] << 16;
case 2: h2 ^= ((unsigned char*)data)[1] << 8;
case 1: h2 ^= ((unsigned char*)data)[0];
h2 *= m;
};
h1 ^= h2 >> 18; h1 *= m;
h2 ^= h1 >> 22; h2 *= m;
h1 ^= h2 >> 17; h1 *= m;
h2 ^= h1 >> 19; h2 *= m;
unsigned long long h = h1;
h = (h << 32) | h2;
return h;
}