天天看點

各種字元串Hash函數比較及各種Hash算法代碼大全

       常用的字元串Hash函數還有ELFHash,APHash等等,都是十分簡單有效的方法。這些函數使用位運算使得每一個字元都對最後的函數值産生影響。另外還有以MD5和SHA1為代表的雜湊函數,這些函數幾乎不可能找到碰撞。

       常用字元串哈希函數有BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash,PJWHash,ELFHash等等。對于以上幾種哈希函數,我對其進行了一個小小的評測。

Hash函數 資料1 資料2 資料3 資料4 資料1得分 資料2得分 資料3得分 資料4得分 平均分
BKDRHash 2 4774 481 96.55 100 90.95 82.05 92.64
APHash 2 3 4754 493 96.55 88.46 100 51.28 86.28
DJBHash 2 2 4975 474 96.55 92.31 100 83.43
JSHash 1 4 4761 506 100 84.62 96.83 17.95 81.94
RSHash 1 4861 505 100 100 51.58 20.51 75.96
SDBMHash 3 2 4849 504 93.1 92.31 57.01 23.08 72.41
PJWHash 30 26 4878 513 43.89 21.95
ELFHash 30 26 4878 513 43.89 21.95

       其中資料1為100000個字母和數字組成的随機串哈希沖突個數。資料2為100000個有意義的英文句子哈希沖突個數。資料3為資料1的哈希值與1000003(大素數)求模後存儲到線性表中沖突的個數。資料4為資料1的哈希值與10000019(更大素數)求模後存儲到線性表中沖突的個數。

        經過比較,得出以上平均得分。平均數為平方平均數。可以發現,BKDRHash無論是在實際效果還是編碼實作中,效果都是最突出的。APHash也是較為優秀的算法。DJBHash,JSHash,RSHash與SDBMHash各有千秋。PJWHash與ELFHash效果最差,但得分相似,其算法本質是相似的。

附1:各種哈希函數的C程式代碼

#define M  249997 
#define M1 1000001 
#define M2 0xF0000000 

// RS Hash Function  
unsigned int RSHash(char*str) 
{ 
    unsigned int b=378551 ; 
    unsigned int a=63689 ; 
    unsigned int hash=0 ;     
    while(*str) 
    { 
        hash=hash*a+(*str++); 
        a*=b ; 
    }     
    return(hash % M); 
} 
 
// JS Hash Function  
unsigned int JSHash(char*str) 
{ 
    unsigned int hash=1315423911 ;    
    while(*str) 
    { 
        hash^=((hash<<5)+(*str++)+(hash>>2)); 
    }      
    return(hash % M); 
} 
 
// P. J. Weinberger Hash Function  
unsigned int PJWHash(char*str) 
{ 
    unsigned int BitsInUnignedInt=(unsigned int)(sizeof(unsigned int)*8); 
    unsigned int ThreeQuarters=(unsigned int)((BitsInUnignedInt*3)/4); 
    unsigned int OneEighth=(unsigned int)(BitsInUnignedInt/8); 
    unsigned int HighBits=(unsigned int)(0xFFFFFFFF)<<(BitsInUnignedInt-OneEighth); 
    unsigned int hash=0 ; 
    unsigned int test=0 ;     
    while(*str) 
    { 
        hash=(hash<<OneEighth)+(*str++); 
        if((test=hash&HighBits)!=0) 
        { 
            hash=((hash^(test>>ThreeQuarters))&(~HighBits)); 
        } 
    }      
    return(hash % M); 
} 
 
// ELF Hash Function  
unsigned int ELFHash(char*str) 
{ 
    unsigned int hash=0 ; 
    unsigned int x=0 ;    
    while(*str) 
    { 
        hash=(hash<<4)+(*str++); 
        if((x=hash&0xF0000000L)!=0) 
        { 
            hash^=(x>>24); 
            hash&=~x ; 
        } 
    }     
    return(hash % M); 
} 
 
// BKDR Hash Function  
unsigned int BKDRHash(char*str) 
{ 
    unsigned int seed=131 ;// 31 131 1313 13131 131313 etc..  
    unsigned int hash=0 ;     
    while(*str) 
    { 
        hash=hash*seed+(*str++); 
    }     
    return(hash % M); 
} 
 
// SDBM Hash Function  
unsigned int SDBMHash(char*str) 
{ 
    unsigned int hash=0 ;     
    while(*str) 
    { 
        hash=(*str++)+(hash<<6)+(hash<<16)-hash ; 
    }     
    return(hash % M); 
} 
 
// DJB Hash Function  
unsigned int DJBHash(char*str) 
{ 
    unsigned int hash=5381 ;    
    while(*str) 
    { 
        hash+=(hash<<5)+(*str++); 
    }      
    return(hash % M); 
} 
 
// AP Hash Function  
unsigned int APHash(char*str) 
{ 
    unsigned int hash=0 ; 
    int i ;      
    for(i=0;*str;i++) 
    { 
        if((i&1)==0) 
        { 
            hash^=((hash<<7)^(*str++)^(hash>>3)); 
        } 
        else  
        { 
            hash^=(~((hash<<11)^(*str++)^(hash>>5))); 
        } 
    }      
    return(hash % M); 
} 
           

附2:Hash算法大全

/**   
* Hash算法大全<br>   
* 推薦使用FNV1算法   
* @algorithm None   
* @author Goodzzp 2006-11-20   
* @lastEdit Goodzzp 2006-11-20    
* @editDetail Create   
*/
public class HashAlgorithms
{
    /**   
    * 加法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   
    * @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 ^ (hash>>10) ^ (hash>>20)) & mask;    
    // 替代:hash %= prime;    

    /**   
    * MASK值,随便找一個值,最好是質數   
    */
    static int M_MASK = 0x8765fed1;
    /**   
    * 一次一個hash   
    * @param key 輸入字元串   
    * @return 輸出hash值   
    */
    public static int oneByOneHash(String key)
    {
        int hash, i;
        for (hash = 0, i = 0; i < key.length(); ++i)
        {
            hash += key.charAt(i);
            hash += (hash << 10);
            hash ^= (hash >> 6);
        }
        hash += (hash << 3);
        hash ^= (hash >> 11);
        hash += (hash << 15);
        //   return (hash & M_MASK);    
        return hash;
    }

    /**   
    * Bernstein's hash   
    * @param key 輸入位元組數組   
    * @param level 初始hash常量   
    * @return 結果hash   
    */
    public 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;
    }

    //    
     Pearson's Hash    
    // char pearson(char[]key, ub4 len, char tab[256])    
    // {    
    //   char hash;    
    //   ub4 i;    
    //   for (hash=len, i=0; i<len; ++i)     
    //     hash=tab[hash^key[i]];    
    //   return (hash);    
    // }    

     CRC Hashing,計算crc,具體代碼見其他    
    // ub4 crc(char *key, ub4 len, ub4 mask, ub4 tab[256])    
    // {    
    //   ub4 hash, i;    
    //   for (hash=len, i=0; i<len; ++i)    
    //     hash = (hash >> 8) ^ tab[(hash & 0xff) ^ key[i]];    
    //   return (hash & mask);    
    // }    

    /**   
    * Universal Hashing   
    */
    public static int universal(char[] key, int mask, int[] tab)
    {
        int hash = key.length, i, len = key.length;
        for (i = 0; i < (len << 3); i += 8)
        {
            char k = key[i >> 3];
            if ((k & 0x01) == 0) hash ^= tab[i + 0];
            if ((k & 0x02) == 0) hash ^= tab[i + 1];
            if ((k & 0x04) == 0) hash ^= tab[i + 2];
            if ((k & 0x08) == 0) hash ^= tab[i + 3];
            if ((k & 0x10) == 0) hash ^= tab[i + 4];
            if ((k & 0x20) == 0) hash ^= tab[i + 5];
            if ((k & 0x40) == 0) hash ^= tab[i + 6];
            if ((k & 0x80) == 0) hash ^= tab[i + 7];
        }
        return (hash & mask);
    }

    /**   
    * Zobrist Hashing   
    */
    public static int zobrist(char[] key, int mask, int[][] tab)
    {
        int hash, i;
        for (hash = key.length, i = 0; i < key.length; ++i)
            hash ^= tab[i][key[i]];
        return (hash & mask);
    }

    // LOOKUP3     
    // 見Bob Jenkins(3).c檔案    

    // 32位FNV算法    
    static int M_SHIFT = 0;
    /**   
    * 32位的FNV算法   
    * @param data 數組   
    * @return int值   
    */
    public static 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;    
    }

    /**   
     * 改進的32位FNV算法1   
     * @param data 數組   
     * @return int值   
     */
    public static int FNVHash1(byte[] data)    
    {    
        final int p = 16777619;    
        int hash = (int)2166136261L;    
        for(byte b:data)    
            hash = (hash ^ b) * p;    
        hash += hash << 13;    
        hash ^= hash >> 7;    
        hash += hash << 3;    
        hash ^= hash >> 17;    
        hash += hash << 5;    
        return hash;    
    }

    /**   
     * 改進的32位FNV算法1   
     * @param data 字元串   
     * @return int值   
     */
    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;    
    }

    /**   
     * Thomas Wang的算法,整數hash   
     */
    public static int intHash(int key)    
    { 
        key += ~(key << 15);    
        key ^= (key >>> 10);    
        key += (key << 3);    
        key ^= (key >>> 6);    
        key += ~(key << 11);    
        key ^= (key >>> 16);    
        return key;    
    }

    /**   
     * RS算法hash   
     * @param str 字元串   
     */
    public 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);
    }
    /* End Of RS Hash Function */

    /**   
     * JS算法   
     */
    public static int JSHash(String str)
    {
        int hash = 1315423911;
        for (int i = 0; i < str.length(); i++)
        {
            hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
        }
        return (hash & 0x7FFFFFFF);
    }
    /* End Of JS Hash Function */

    /**   
     * PJW算法   
     */
    public static int PJWHash(String str)
    {
        int BitsInUnsignedInt = 32;
        int ThreeQuarters = (BitsInUnsignedInt * 3) / 4;
        int OneEighth = BitsInUnsignedInt / 8;
        int HighBits = 0xFFFFFFFF << (BitsInUnsignedInt - OneEighth);
        int hash = 0;
        int 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 & 0x7FFFFFFF);
    }
    /* End Of P. J. Weinberger Hash Function */

    /**   
     * ELF算法   
     */
    public static int ELFHash(String str)
    {
        int hash = 0;
        int x = 0;
        for (int i = 0; i < str.length(); i++)
        {
            hash = (hash << 4) + str.charAt(i);
            if ((x = (int)(hash & 0xF0000000L)) != 0)
            {
                hash ^= (x >> 24);
                hash &= ~x;
            }
        }
        return (hash & 0x7FFFFFFF);
    }
    /* End Of ELF Hash Function */

    /**   
     * BKDR算法   
     */
    public static int BKDRHash(String str)
    {
        int seed = 131; // 31 131 1313 13131 131313 etc..    
        int hash = 0;
        for (int i = 0; i < str.length(); i++)
        {
            hash = (hash * seed) + str.charAt(i);
        }
        return (hash & 0x7FFFFFFF);
    }
    /* End Of BKDR Hash Function */

    /**   
     * SDBM算法   
     */
    public static int SDBMHash(String str)
    {
        int hash = 0;
        for (int i = 0; i < str.length(); i++)
        {
            hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
        }
        return (hash & 0x7FFFFFFF);
    }
    /* End Of SDBM Hash Function */

    /**   
     * DJB算法   
     */
    public static int DJBHash(String str)
    {
        int hash = 5381;
        for (int i = 0; i < str.length(); i++)
        {
            hash = ((hash << 5) + hash) + str.charAt(i);
        }
        return (hash & 0x7FFFFFFF);
    }
    /* End Of DJB Hash Function */

    /**   
     * DEK算法   
     */
    public static int DEKHash(String str)
    {
        int hash = str.length();
        for (int i = 0; i < str.length(); i++)
        {
            hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
        }
        return (hash & 0x7FFFFFFF);
    }
    /* End Of DEK Hash Function */

    /**   
     * AP算法   
     */
    public static int APHash(String str)
    {
        int hash = 0;
        for (int i = 0; i < str.length(); i++)
        {
            hash ^= ((i & 1) == 0) ? ((hash << 7) ^ str.charAt(i) ^ (hash >> 3)) :
                                     (~((hash << 11) ^ str.charAt(i) ^ (hash >> 5)));
        }
        //       return (hash & 0x7FFFFFFF);    
        return hash;
    }
    /* End Of AP Hash Function */

    /**   
     * JAVA自己帶的算法   
     */
    public static int java(String str)
    {
        int h = 0;
        int off = 0;
        int len = str.length();
        for (int i = 0; i < len; i++)
        {
            h = 31 * h + str.charAt(off++);
        }
        return h;
    }

    /**   
     * 混合hash算法,輸出64位的值   
     */
    public static long mixHash(String str)
    {
        long hash = str.hashCode();
        hash <<= 32;
        hash |= FNVHash1(str);
        return hash;
    }
}
           

繼續閱讀