文章转摘自http://www.cmykrgb123.cn/blog/string-hash-compare/
常用的字符串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效果最差,但得分相似,其算法本质是相似的。
在信息修竞赛中,要本着易于编码调试的原则,个人认为BKDRHash是最适合记忆和使用的。
CmYkRgB123原创,欢迎建议、交流、批评和指正。
附:各种哈希函数的C语言程序代码
{
unsigned int hash = 0;
while (*str)
{
// equivalent to: hash = 65599*hash + (*str++);
hash = (*str++) + (hash << 6) + (hash << 16) - hash;
}
return (hash & 0x7FFFFFFF);
}
// RS Hash
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 & 0x7FFFFFFF);
}
// JS Hash
unsigned int JSHash(char *str)
{
unsigned int hash = 1315423911;
while (*str)
{
hash ^= ((hash << 5) + (*str++) + (hash >> 2));
}
return (hash & 0x7FFFFFFF);
}
// P. J. Weinberger Hash
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 unsigned int SDBMHash(char *str)
- 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);
}
字符串的算法一般大公司都会考到,我们首先要想到高效的hash。如百度查找一组字符串是否出现在某个文本中,这个不是考什么kmp,他们想听到的是hash。趋势科技考的是从某个文本中删除一组字符串,我想也是要hash吧。
1 概述
链表查找的时间效率为O(N),二分法为log2N,B+ Tree为log2N,但Hash链表查找的时间效率为O(1)。 |
设计高效算法往往需要使用Hash链表,常数级的查找速度是任何别的算法无法比拟的,Hash链表的构造和冲突的不同实现方法对效率当然有一定的影响,然 而Hash函数是Hash链表最核心的部分,本文尝试分析一些经典软件中使用到的字符串Hash函数在执行效率、离散性、空间利用率等
方面的性能问题。
作者阅读过大量经典软件原代码,下面分别介绍几个经典软件中出现的字符串Hash函数。 |
static unsigned long hashpjw(char *arKey, unsigned int nKeyLength) |
char *arEnd=arKey+nKeyLength; |
if ((g = (h & 0xF0000000))) { |
unsigned long lh_strhash(char *str) |
if (str == NULL) return(0); |
/* The following hash seems to work very well on normal text strings |
* no collisions on /usr/dict/words and it distributes on %2^n quite |
* well, not as good as MD5, but still good. |
unsigned long lh_strhash(const char *c) |
if ((c == NULL) || (*c == '\0')) |
return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24)); |
在下面的测量过程中我们分别将上面的两个函数标记为OpenSSL_Hash1和OpenSSL_Hash2,至于上面的实现中使用MD5算法的实现函数我们不作测试。 |
/* Calc hash for a key */ |
static uint calc_hashnr(const byte *key,uint length) |
register uint nr=1, nr2=4; |
nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8); |
/* Calc hash for a key, case indepenently */ |
static uint calc_hashnr_caseup(const byte *key,uint length) |
register uint nr=1, nr2=4; |
nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8); |
* The basis of the hash algorithm was taken from an idea sent by email to the |
* IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and |
* Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com) |
* later improved on their algorithm. |
* The magic is in the interesting relationship between the special prime |
* 16777619 (2^24 + 403) and 2^32 and 2^8. |
* This hash produces the fewest collisions of any that we've seen so |
* far, and works well on both numbers and strings. |
uint calc_hashnr(const byte *key, uint len) |
for (hash = 0; key < end; key++) |
hash ^= (uint) *(uchar*) key; |
uint calc_hashnr_caseup(const byte *key, uint len) |
for (hash = 0; key < end; key++) |
hash ^= (uint) (uchar) toupper(*key); |
Mysql中对字符串Hash函数还区分了大小写,我们的测试中使用不区分大小写的字符串Hash函数,另外我们将上面的两个函数分别记为MYSQL_Hash1和MYSQL_Hash2。 |
unsigned int hash(char *str) |
register unsigned char *p; |
for(h=0, p = (unsigned char *)str; *p ; p++) |
从上面给出的经典字符串Hash函 数中可以看出,有的涉及到字符串大小敏感问题,我们的测试中只考虑字符串大小写敏感的函数,另外在上面的函数中有的函数 需要长度参数,有的不需要长度参数,这对函数本身的效率有一定的影响,我们的测试中将对函数稍微作一点修改,全部使用长度参数,并将函数内部出现的计算长 度代码删除。 |
我们用来作测试用的Hash链表采用经典的拉链法解决冲突,另外我们采用静态分配桶(Hash链表长度)的方法来构造Hash链表,这主要是为了简化我们的实现,并不影响我们的测试结果。 |
测试文本采用单词表,测试过程中从一个输入文件中读取全部不重复单词构造一个Hash表,测试内容分别是函数总调用次数、函数总调用时间、最大拉链长度、 平均拉链长度、桶利用率(使用过的桶所占的比率),其中函数总调用次数是指Hash函数被调用的总次数,为了测试出函数执行时间,该值在测试过程中作了一 定的放大,函数总调用时间是指Hash函数总的执行时间,最大拉链长度是指使用拉链法构造链表过程中出现的最大拉链长度,平均拉链长度指拉链的平均长度。 |
PIII600笔记本,128M内存,windows 2000 server操作系统。 |
以下分别是对两个不同文本文件中的全部不重复单词构造Hash链表的测试结果,测试结果中函数调用次数放大了100倍,相应的函数调用时间也放大了100倍。 |
从上表可以看出,这些经典软件虽然构造字符串Hash函数的方法不同,但是它们的效率都是不错的,相互之间差距很小,读者可以参考实际情况从其中借鉴使用。
分享到:
相关推荐
实验设计优化字符串哈希函数 比较经典字符串哈希函数 采用斐波那契函数思想
用C语言实现常用的字符串哈希函数,比如RSHash、JSHash、PJWHash、FNVHash等
几个经典的字符串哈希函数及测试.rar
将字符串哈希成数字的几种经典的方法:其中的一部分 #ifndef INCLUDE_GENERALHASHFUNCTION_C_H #define INCLUDE_GENERALHASHFUNCTION_C_H #include typedef unsigned int (*hash_function)(char*, unsigned int...
dwHashType = 0时计算的哈希值用于确定字符串在哈希表中的位置; dwHashType = 1,dwHashType = 2时计算的哈希值用于验证字符串 返回值:字符串的哈希值 */ unsigned long HashString(char *lpszString, ...
hash字符串函数总结,挥泪大放送,绝对全面,各类总结。
毕业论文:哈希函数的构造方法,仅供参考。毕业论文 哈希函数
平时收集的一些哈希函数,用于多种不同的环境
本文介绍了目前主流的一些字符串哈希算法,能够对开发过程中的一些针对字符串的哈希结构有指导作用
用C++实现的完美哈希函数,打印C语言的32个关键字的哈希值,并且判断所输入的字符串是否为关键字
字符串哈希算法和内存监控类,暂时放一下,还在开发中
目前比较有名的哈希函数 C语言 数据结构
用三个哈希值处理字符串,解决其在矩阵中出现次数问题,利用了矩阵的旋转
TLSH 一个生成字符串哈希的 JavaScript 库。它的特点是,字符串越相似,或者重复同样的模式,生成的哈希也越相似,可以用来计算两个字符串的相似程度。
如今越来越多的物联网设备带来了对哈希函数的需求,而传统的哈希函数又因为资源受限而不能直接应用,所以必须得针对该类设备重新设计,提出了一种新的轻量哈希函数HBL(Hash Function Based on LEA),它采用了主流...
用C语言实现MD5哈希函数,它是将文件的每一行进行MD5加密,输出一个128位的哈希值。
本文实例讲述了C#计算字符串哈希值(MD5、SHA)的方法。分享给大家供大家参考。具体如下: 一、关于本文 本文中是一个类库,包括下面几个函数: ① 计算32位MD5码(大小写):Hash_MD5_32 ② 计算16位MD5码(大小写...
哈希函数与数据完整性
45哈希值校验值计算器是一款可以支持计算字符串的哈希值。 支持: 计算字符串的哈希值校验值,计算文件的哈希值校验值, 支持MD5,CRC32,SHA1(160),SHA-224,SHA-256,SHA-384,SHA-512算法, 优点: 支持算法多,本...