原文
+ C6 n3 r. T! E, x% M+ O8 m! chttp://blog.csai.cn/user3/50125/archives/2009/35638.html
# B$ \8 ~8 }, v! |9 L3 |' F9 ]; H1 e& e8 b
[pre]文章转摘自http://www.cmykrgb123.cn/blog/string-hash-compare/
( a3 f) D2 g( K+ A$ r0 z; ^
, c8 o; R Z; F常用的字符串Hash函数还有ELFHash,APHash等等,都是十分简单有效的方法。这些函数使用 ! u9 c1 o8 l, D! z6 e
位运算使得每一个字符都对最后的函数值产生影响。另外还有以MD5和SHA1为代表的杂凑函数, 9 n) d" t9 K7 x$ v
这些函数几乎不可能找到碰撞。 A; S! |4 o0 b3 c. p
常用字符串哈希函数有BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash, ) p0 P+ p+ Q) Y j
PJWHash,ELFHash等等。对于以上几种哈希函数,我对其进行了一个小小的评测。
* D, \8 E) p8 WHash函数 | 数据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 | 7 R9 J N% p+ Q! d, G# x
其中数据1为100000个字母和数字组成的随机串哈希冲突个数。数据2为100000个有意义的英文句 . U$ I* J( @4 M
子哈希冲突个数。数据3为数据1的哈希值与1000003(大素数)求模后存储到线性表中冲突的个数。
( W$ w$ M$ w( s" j7 N数据4为数据1的哈希值与10000019(更大素数)求模后存储到线性表中冲突的个数。 * G" M* z/ u; N3 v6 V2 F
经过比较,得出以上平均得分。平均数为平方平均数。可以发现,BKDRHash无论是在实际效果还是 . W: T6 I- q! a1 Z( Z
编码实现中,效果都是最突出的。APHash也是较为优秀的算法。DJBHash,JSHash,RSHash与
; U e1 `/ u+ W: t1 Q E) \SDBMHash各有千秋。PJWHash与ELFHash效果最差,但得分相似,其算法本质是相似的。 2 K; ?* A) x9 M. L* X
在信息修竞赛中,要本着易于编码调试的原则,个人认为BKDRHash是最适合记忆和使用的。
% ^) X: v( H/ E4 {0 {* w9 [6 MCmYkRgB123原创,欢迎建议、交流、批评和指正。
5 i: { g6 J. A6 _! ] . P) H y, S+ v. P* Y; ^" S
附:各种哈希函数的C语言程序代码 - q' N: I: E; U4 W/ c
, B3 G6 F4 B" `9 p7 F
unsigned int SDBMHash(char *str)
- k; G& r; m) q# R1 J{ 9 h. T X4 c1 u" y9 j( U- d' T( k
unsigned int hash = 0;
/ K4 u& Y q2 d1 N4 F
% r8 O. l# c9 N7 [, f0 j while (*str) 7 w7 o! E* M( A+ p
{ . Y) n6 _ U! R( E" {
// equivalent to: hash = 65599*hash + (*str++); 4 c8 ]0 p5 ?- c/ G, @6 {$ S# j
hash = (*str++) + (hash << 6) + (hash << 16) - hash; / ^# [8 c r6 z
}
! ^9 H; Z6 E; @+ R, H; L
; D) { L K0 G return (hash & 0x7FFFFFFF);
4 O1 G' P' {2 n2 U ^' q2 u+ u+ ?} , \* b& h# `9 j# L9 k" e
D, U* s N8 `! ?8 o( h
// RS Hash ' n: O1 |- \" r2 ]. Q( I
unsigned int RSHash(char *str)
& K6 f9 {. O' a) v: `{
9 u9 p: x8 G8 }2 `/ ~" S; n$ Q5 O I unsigned int b = 378551;
4 f# L* l. r: {, I3 N unsigned int a = 63689;
: L( e8 m. M7 J8 w6 m) Y9 T9 { unsigned int hash = 0; 5 e5 }5 \/ _0 ^; U
6 s$ ^7 r4 j: q+ u3 n
while (*str)
8 x0 s5 {: J0 C* P {
e% I! @! X% [2 o hash = hash * a + (*str++);
3 u% `! D* J+ W* J% _' ^ a *= b; 7 B' C( p$ L; J+ _9 c, k
}
- l2 M4 e+ r; ?4 e- t ! H5 n8 I; X3 N* q/ V
return (hash & 0x7FFFFFFF);
3 B e9 H: X( V4 s6 j} 4 _1 f& H0 N% Y( _
# j3 S8 ?* s: `4 s# o
// JS Hash
# Q7 l8 n" E, G) P) g0 k6 W1 i# funsigned int JSHash(char *str) * Y4 ~8 |& n0 ?) L. `2 N
{
( e" H5 ?1 H m2 ^9 {+ } unsigned int hash = 1315423911; 6 T# h4 q! U1 b+ _9 K( ]$ P; z& f
{$ ^. G. K: c% C9 R while (*str)
' M q) M8 _ G { ' @6 E- f$ h1 f7 X4 \
hash ^= ((hash << 5) + (*str++) + (hash >> 2)); , T2 e4 l2 n! ~
}
g& |) g! ?8 T, n/ J- o
" W% H0 ]! i5 H4 [ return (hash & 0x7FFFFFFF); ! s% D7 y2 r! Z
}
7 Q* k( I. v- [3 W5 ~
3 s' s0 h- i9 Q! I// P. J. Weinberger Hash - L4 O4 ]* I4 g, m* o# b4 I
unsigned int PJWHash(char *str): |7 b7 s: @7 ?3 Q. K1 V3 x8 j+ L
{+ N: U7 A% {+ p# ]
unsigned int BitsInUnignedInt = (unsigned int)(sizeof(unsigned int) * 8);
- h1 ^1 ^" [% A$ a- S3 b unsigned int ThreeQuarters = (unsigned int)((BitsInUnignedInt * 3) / 4);
+ H' e9 E, a4 Z( @ unsigned int OneEighth = (unsigned int)(BitsInUnignedInt / 8);) J7 p s% E% L# a q1 ^/ }
unsigned int HighBits = (unsigned int)(0xFFFFFFFF) << (BitsInUnignedInt [pre] - 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 & 0x7FFFFFFF);} // ELF Hash 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 & 0x7FFFFFFF);} // BKDR Hash 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 & 0x7FFFFFFF);} // DJB Hash unsigned int DJBHash(char *str){ unsigned int hash = 5381; while (*str) { hash += (hash << 5) + (*str++); } return (hash & 0x7FFFFFFF);} // AP Hash 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 & 0x7FFFFFFF);}[/pre] |