常用的字串Hash函數還有ELFHash,APHash等等,都是十分簡單有效方法。這些函數使用位元運算使得每一個字元都對最後的函數值產生影響。另外還有以MD5和SHA1為代表的雜湊函數,這些函數幾乎不可能找到碰撞。
常用字串雜湊函數有BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash,PJWHash,ELFHash等等。對於以上幾種雜湊函數,我對其進行了一個小小的評測。
| Hash函數 |
資料1 |
資料2 |
資料3 |
資料4 |
資料1得分 |
資料2得分 |
資料3得分 |
資料4得分 |
平均分 |
| BKDRHash |
2 |
0 |
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 |
0 |
100 |
83.43 |
| JSHash |
1 |
4 |
4761 |
506 |
100 |
84.62 |
96.83 |
17.95 |
81.94 |
| RSHash |
1 |
0 |
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 |
0 |
0 |
43.89 |
0 |
21.95 |
| ELFHash |
30 |
26 |
4878 |
513 |
0 |
0 |
43.89 |
0 |
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; }}