设为首页收藏本站官方微博

汉化资料 字符串hash算法比较

[复制链接]
查看: 1521|回复: 0
打印 上一主题 下一主题

[汉化资料] 字符串hash算法比较

跳转到指定楼层
楼主
发表于 2010-5-20 11:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

字符串hash算法比较

原文( k# }, |4 f+ ?3 o: l- j- r, n
http://blog.csdn.net/tarmee/archive/2007/08/16/1746442.aspx
/ {! O/ x4 c; H: J2 @
8 q) R! v9 p6 }* F, b, m字符串的算法一般大公司都会考到,我们首先要想到高效的hash。如百度查找一组字符串是否出现在某个文本中,这个不是考什么kmp,他们想听到的是hash。趋势科技考的是从某个文本中删除一组字符串,我想也是要hash吧。& y3 V" B) `* w; D8 L2 P5 D
1 概述
! j! j, e" n) W8 l+ ]2 a- @) V
链表[size=+0]查找的时间效率为O(N),二分法为log2N,B+ Tree为log2N,但[size=+0]Hash链表[size=+0]查找的时间效率为O(1)。
设计高效算法往往需要使用[size=+0]Hash链表,常数级的[size=+0]查找速度是任何别的算法无法比拟的,[size=+0]Hash链表的构造和冲突的不同实现方法对效率当然有一定的影响,然 而[size=+0]Hash函数是[size=+0]Hash链表最核心的部分,本文尝试分析一些经典软件中使用到的字符串[size=+0]Hash函数在执行效率、离散性、空间利用率等方面的性能问题。 1 l. N1 g1 E3 m+ D9 d
2 经典字符串[size=+0]Hash函数介绍
作者阅读过大量经典软件原代码,下面分别介绍几个经典软件中出现的字符串[size=+0]Hash函数。
2.1 PHP中出现的字符串[size=+0]Hash函数
static unsigned long [size=+0]hashpjw(char *arKey, unsigned int nKeyLength)
{
unsigned long h = 0, g;
char *arEnd=arKey+nKeyLength;
& a0 Y- _8 J7 e# }
while (arKey < arEnd) {
h = (h << 4) + *arKey++;
if ((g = (h & 0xF0000000))) {
h = h ^ (g >> 24);
h = h ^ g;
}
}
return h;
}
2.2 OpenSSL中出现的字符串[size=+0]Hash函数
unsigned long lh_str[size=+0]hash(char *str)
{
int i,l;
unsigned long ret=0;
unsigned short *s;
5 {) C/ U! X" U2 Q, c/ d& D
if (str == NULL) return(0);
l=(strlen(str)+1)/2;
s=(unsigned short *)str;
for (i=0; i
ret^=(s<<(i&0x0f));
return(ret);
} */

. p. B9 C# ~9 h& L
/* The following [size=+0]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_str[size=+0]hash(const char *c)
{
unsigned long ret=0;
long n;
unsigned long v;
int r;

/ w+ j' v/ f- t$ O6 B  g. z
if ((c == NULL) || (*c == '\0'))
return(ret);
/*
unsigned char b[16];
MD5(c,strlen(c),b);
return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));
*/

- r9 z, n7 t0 A8 }0 C8 J# w% o
n=0x100;
while (*c)
{
v=n|(*c);
n+=0x100;
r= (int)((v>>2)^v)&0x0f;
ret=(ret(32-r));
ret&=0xFFFFFFFFL;
ret^=v*v;
c++;
}
return((ret>>16)^ret);
}
在下面的测量过程中我们分别将上面的两个函数标记为OpenSSL_[size=+0]Hash1和OpenSSL_[size=+0]Hash2,至于上面的实现中使用MD5算法的实现函数我们不作测试。
2.3 MySql中出现的字符串[size=+0]Hash函数
#ifndef NEW_[size=+0]HASH_FUNCTION

9 y5 o8 I1 K, u  e8 |" a  i+ k
/* Calc [size=+0]hashvalue for a key */
5 Z2 T4 y2 v! A% o  y
static uint calc_[size=+0]hashnr(const byte *key,uint length)
{
register uint nr=1, nr2=4;
while (length--)
{
nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8);
nr2+=3;
}
return((uint) nr);
}

2 h7 L8 i. F+ Q, |& \* u
/* Calc [size=+0]hashvalue for a key, case indepenently */
' t& I$ y+ e; d' E, R2 H
static uint calc_[size=+0]hashnr_caseup(const byte *key,uint length)
{
register uint nr=1, nr2=4;
while (length--)
{
nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);
nr2+=3;
}
return((uint) nr);
}

) p! I7 ^" A1 K$ i9 q
#else
9 b9 {& ~2 U5 A( x8 ]6 ?
/*
* Fowler/Noll/Vo [size=+0]hash
*
* The basis of the [size=+0]hash algorithm was taken from an idea sent by email to the
* IEEE Posix P1003.2 mailing list from Phong Vo ([email protected]) and
* Glenn Fowler ([email protected]). Landon Curt Noll ([email protected])
* 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 [size=+0]hash produces the fewest collisions of any function that we've seen so
* far, and works well on both numbers and strings.
*/

7 S4 R! v- P. O0 P* G) B. S
uint calc_[size=+0]hashnr(const byte *key, uint len)
{
const byte *end=key+len;
uint [size=+0]hash;
for ([size=+0]hash = 0; key < end; key++)
{
[size=+0]hash *= 16777619;
[size=+0]hash ^= (uint) *(uchar*) key;
}
return ([size=+0]hash);
}

+ q( ?: Y7 E: F$ U
uint calc_[size=+0]hashnr_caseup(const byte *key, uint len)
{
const byte *end=key+len;
uint [size=+0]hash;
for ([size=+0]hash = 0; key < end; key++)
{
[size=+0]hash *= 16777619;
[size=+0]hash ^= (uint) (uchar) toupper(*key);
}
return ([size=+0]hash);
}

" e' d# o9 d9 Y9 H/ @# }; j& W0 x% B
#endif
Mysql中对字符串[size=+0]Hash函数还区分了大小写,我们的测试中使用不区分大小写的字符串[size=+0]Hash函数,另外我们将上面的两个函数分别记为MYSQL_[size=+0]Hash1和MYSQL_[size=+0]Hash2。
2.4 另一个经验字符串[size=+0]Hash函数
unsigned int [size=+0]hash(char *str)
{
register unsigned int h;
register unsigned char *p;

6 b8 O8 J; i* }
for(h=0, p = (unsigned char *)str; *p ; p++)
h = 31 * h + *p;
) U" E* v* r: p5 |& J
return h;
}
3 测试及结果
3.1 测试说明
从上面给出的经典字符串[size=+0]Hash函数中可以看出,有的涉及到字符串大小敏感问题,我们的测试中只考虑字符串大小写敏感的函数,另外在上面的函数中有的函数 需要长度参数,有的不需要长度参数,这对函数本身的效率有一定的影响,我们的测试中将对函数稍微作一点修改,全部使用长度参数,并将函数内部出现的计算长 度代码删除。
我们用来作测试用的[size=+0]Hash链表采用经典的拉链法解决冲突,另外我们采用静态分配桶([size=+0]Hash链表长度)的方法来构造[size=+0]Hash链表,这主要是为了简化我们的实现,并不影响我们的测试结果。
测试文本采用单词表,测试过程中从一个输入文件中读取全部不重复单词构造一个[size=+0]Hash表,测试内容分别是函数总调用次数、函数总调用时间、最大拉链长度、 平均拉链长度、桶利用率(使用过的桶所占的比率),其中函数总调用次数是指[size=+0]Hash函数被调用的总次数,为了测试出函数执行时间,该值在测试过程中作了一 定的放大,函数总调用时间是指[size=+0]Hash函数总的执行时间,最大拉链长度是指使用拉链法构造链表过程中出现的最大拉链长度,平均拉链长度指拉链的平均长度。
测试过程中使用的机器配置如下:
PIII600笔记本,128M内存,windows 2000 server操作系统。
3.2 测试结果
以下分别是对两个不同文本文件中的全部不重复单词构造[size=+0]Hash链表的测试结果,测试结果中函数调用次数放大了100倍,相应的函数调用时间也放大了100倍。
从上表可以看出,这些经典软件虽然构造字符串[size=+0]Hash函数的方法不同,但是它们的效率都是不错的,相互之间差距很小,读者可以参考实际情况从其中借鉴使用。 " e9 i  J2 t7 y$ @! a+ }
/ K5 D" A# P, M, ^2 |
http://hi.baidu.com/wertywang/blog/item/1fe7d2ee1faaed282cf5340f.html
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

冒险解谜游戏中文网 ChinaAVG

官方微博官方微信号小黑屋 微信玩家群  

(C) ChinaAVG 2004 - 2019 All Right Reserved. Powered by Discuz! X3.2
辽ICP备11008827号 | 桂公网安备 45010702000051号

冒险,与你同在。 冒险解谜游戏中文网ChinaAVG诞生于2004年9月9日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

快速回复 返回顶部 返回列表