Hash演算法有哪些?
阿新 • • 發佈:2020-10-14
轉載:https://www.jianshu.com/p/958eb591ecd6
Hash演算法的有哪幾種,優缺點,使用場景
Hash ,一般叫做雜湊演算法,就是把任意長度的輸入通過雜湊演算法,變換成固定長度的輸入,相當於一種壓縮對映,將任意長度的訊息壓縮到某一固定長度的訊息摘要的函式。
• 加法Hash;把輸入元素一個一個的加起來構成最後的結果
/** * 加法hash * * @param key * 字串 * @param prime * 一個質數 * @return hash結果 */ public static intadditiveHash(String key, int prime) { int hash, i; for (hash = key.length(), i = 0; i < key.length(); i++) hash += key.charAt(i); return (hash % prime); }
• 位運算Hash;這型別Hash函式通過利用各種位運算(常見的是移位和異或)來充分的混合輸入元素
/** * 旋轉hash * * @param key * 輸入字串 * @param prime * 質數 *• 乘法Hash;這種型別的Hash函式利用了乘法的不相關性(乘法的這種性質,最有名的莫過於平方取頭尾的隨機數生成演算法,雖然這種演算法效果並不好);@return hash值 */ public static int rotatingHash(String key, int prime) { int hash, i; for (hash = key.length(), i = 0; i < key.length(); ++i) hash = (hash << 4) ^ (hash >> 28) ^ key.charAt(i); return (hash % prime); // return (hash ^ (hash>>10) ^ (hash>>20)); }
staticint bernstein(String key) { int hash = 0; int i; for (i=0; i<key.length(); ++i) hash = 33*hash + key.charAt(i); return hash; }
jdk5.0裡面的String類的hashCode()方法也使用乘法Hash;32位FNV演算法
int M_SHIFT = 0; public int FNVHash(byte[] data) { int hash = (int) 2166136261L; for(byte b : data) hash = (hash * 16777619) ^ b; if(M_SHIFT == 0) return hash; return (hash ^ (hash >> M_SHIFT)) & M_MASK; }
改進後的 FNV 演算法
public static int FNVHash1(String data) { final int p = 16777619; int hash = (int) 2166136261L; for (int i = 0; i < data.length(); i++) hash = (hash ^ data.charAt(i)) * p; hash += hash << 13; hash ^= hash >> 7; hash += hash << 3; hash ^= hash >> 17; hash += hash << 5; return hash; }
常見的還有乘以一個不斷改變的數
static int RSHash(String str) { int b = 378551; int a = 63689; int hash = 0; for (int i = 0; i < str.length(); i++) { hash = hash * a + str.charAt(i); a = a * b; } return (hash & 0x7FFFFFFF); }
• 除法Hash;除法和乘法一樣,同樣具有表面上看起來的不相關性。不過,因為除法太慢,這種方式幾乎找不到真正的應用
• 查表Hash;查表Hash最有名的例子莫過於CRC系列演算法。雖然CRC系列演算法本身並不是查表,但是,查表是它的一種最快的實現方式。查表Hash中有名的例子有:Universal Hashing和Zobrist Hashing。他們的表格都是隨機生成的。
• 混合Hash;混合Hash演算法利用了以上各種方式。各種常見的Hash演算法,比如MD5、Tiger都屬於這個範圍。它們一般很少
- 陣列 hash
inline int hashcode(const int *v) { int s = 0; for(int i=0; i<k; i++) s=((s<<2)+(v[i]>>4))^(v[i]<<10); s = s % M; s = s < 0 ? s + M : s; return s; }
在面向查詢的Hash函式裡面使用
環 hash
環 hash 計算步驟
- 首先求出雜湊值, 並將其分配到 0~2^32 的圓上,其實把機器編號 hash 到這個環上。
- 採用同樣的方法求出儲存資料鍵的雜湊值,並對映到相同的圓上
- 然後從資料對映到位置開始順時針開始找,將資料儲存到找到的第一個伺服器,如果 2^32 仍然找不到伺服器,就會儲存到第一臺伺服器上。
環 hash 存在的問題
資料傾斜問題
資料傾斜是指,當機器不多時,幾臺機器在環上面貼的很近,分佈是不是很均勻,會導致大部分資料集中到這幾臺機器上,這樣就產生了資料傾斜問題。
如何解決資料傾斜問題?
引入了虛擬機器器概念,一臺機器需要在環上映射出多個這個位置,比如 我們用機器的 ip 來 hash ,這樣就實現了一臺物理機映射出多個虛擬機器器的編號。