Hash算法有哪些?


轉載: 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));
}
• 乘法Hash;這種類型的Hash函數利用了乘法的不相關性(乘法的這種性質,最有名的莫過於平方取頭尾的隨機數生成算法,雖然這種算法效果並不好);
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 計算步驟

  1. 首先求出哈希值, 並將其分配到 0~2^32 的圓上,其實把機器編號 hash 到這個環上。
  2. 采用同樣的方法求出存儲數據鍵的哈希值,並映射到相同的圓上
  3. 然后從數據映射到位置開始順時針開始找,將數據保存到找到的第一個服務器,如果 2^32 仍然找不到服務器,就會保存到第一台服務器上。
 
圖片.png

環 hash 存在的問題

數據傾斜問題

數據傾斜是指,當機器不多時,幾台機器在環上面貼的很近,分布是不是很均勻,會導致大部分數據集中到這幾台機器上,這樣就產生了數據傾斜問題。

如何解決數據傾斜問題?

引入了虛擬機器概念,一台機器需要在環上映射出多個這個位置,比如 我們用機器的 ip 來 hash ,這樣就實現了一台物理機映射出多個虛擬機器的編號。

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM