轉載: https://www.jianshu.com/p/958eb591ecd6
Hash算法的有哪幾種,優缺點,使用場景
Hash ,一般叫做散列算法,就是把任意長度的輸入通過散列算法,變換成固定長度的輸入,相當於一種壓縮映射,將任意長度的消息壓縮到某一固定長度的消息摘要的函數。
• 加法Hash;把輸入元素一個一個的加起來構成最后的結果
/** * 加法hash * * @param key * 字符串 * @param prime * 一個質數 * @return hash結果 */ public static int additiveHash(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 * 質數 * @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)); }
static int 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 ,這樣就實現了一台物理機映射出多個虛擬機器的編號。