原文
4 i9 R+ F' o" g+ \http://blog.csdn.net/tarmee/archive/2007/08/16/1746442.aspx
# ?/ X6 W) W& [6 v. O$ g
5 Q, I; R0 d4 g! ~/ c+ T字符串的算法一般大公司都会考到,我们首先要想到高效的hash。如百度查找一组字符串是否出现在某个文本中,这个不是考什么kmp,他们想听到的是hash。趋势科技考的是从某个文本中删除一组字符串,我想也是要hash吧。7 D% N/ C1 _) V8 p7 r5 n
1 概述 / C& Q" ?% O. z: J( q4 ]6 W) y
链表[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函数在执行效率、离散性、空间利用率等方面的性能问题。
' Z* B+ r- _2 H/ P& H作者阅读过大量经典软件原代码,下面分别介绍几个经典软件中出现的字符串[size=+0]Hash函数。 |
2.1 PHP中出现的字符串[size=+0]Hash函数 |
static unsigned long [size=+0]hashpjw(char *arKey, unsigned int nKeyLength) |
char *arEnd=arKey+nKeyLength; |
$ j$ K8 p/ a! w: }* f0 H3 C- U
|
while (arKey < arEnd) { |
h = (h << 4) + *arKey++; |
if ((g = (h & 0xF0000000))) { |
2.2 OpenSSL中出现的字符串[size=+0]Hash函数 |
unsigned long lh_str[size=+0]hash(char *str) |
if (str == NULL) return(0); |
ret^=(s<<(i&0x0f)); |
/* 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) |
if ((c == NULL) || (*c == '\0')) |
return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24)); |
r= (int)((v>>2)^v)&0x0f; |
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 |
8 b- F: I. U" G) O+ N5 G. p
|
/* Calc [size=+0]hashvalue for a key */ |
' `1 G [/ q1 o7 d/ p3 L; a" L |
static uint calc_[size=+0]hashnr(const byte *key,uint length) |
register uint nr=1, nr2=4; |
nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8); |
% y, _6 K. }2 v/ C/ L' `0 |" K" ? |
/* Calc [size=+0]hashvalue for a key, case indepenently */ |
static uint calc_[size=+0]hashnr_caseup(const byte *key,uint length) |
register uint nr=1, nr2=4; |
nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8); |
% T1 A8 t" X- }4 g: U9 |8 F- a
|
* Fowler/Noll/Vo [size=+0]hash |
* The basis of the [size=+0]hash algorithm was taken from an idea sent by email to the |
* 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. |
% C0 M8 E# d9 n H% Q7 t* n
|
uint calc_[size=+0]hashnr(const byte *key, uint len) |
for ([size=+0]hash = 0; key < end; key++) |
[size=+0]hash *= 16777619; |
[size=+0]hash ^= (uint) *(uchar*) key; |
uint calc_[size=+0]hashnr_caseup(const byte *key, uint len) |
for ([size=+0]hash = 0; key < end; key++) |
[size=+0]hash *= 16777619; |
[size=+0]hash ^= (uint) (uchar) toupper(*key); |
/ i9 Y7 T/ y3 j) f! f9 ?8 M3 g
|
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 char *p; |
for(h=0, p = (unsigned char *)str; *p ; p++) |
' K5 \& t% a9 }& E1 N) B$ M$ `
|
从上面给出的经典字符串[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操作系统。 |
以下分别是对两个不同文本文件中的全部不重复单词构造[size=+0]Hash链表的测试结果,测试结果中函数调用次数放大了100倍,相应的函数调用时间也放大了100倍。 | 从上表可以看出,这些经典软件虽然构造字符串[size=+0]Hash函数的方法不同,但是它们的效率都是不错的,相互之间差距很小,读者可以参考实际情况从其中借鉴使用。
t' U H1 t8 {! J* u/ E' e
7 }" ?% P+ o( uhttp://hi.baidu.com/wertywang/blog/item/1fe7d2ee1faaed282cf5340f.html |