论坛交流
首页办公自动化| 网页制作| 平面设计| 动画制作| 数据库开发| 程序设计| 全部视频教程
应用视频: Windows | Word2007 | Excel2007 | PowerPoint2007 | Dreamweaver 8 | Fireworks 8 | Flash 8 | Photoshop cs | CorelDraw 12
编程视频: C语言视频教程 | HTML | Div+Css布局 | Javascript | Access数据库 | Asp | Sql Server数据库Asp.net  | Flash AS
当前位置 > 文字教程 > C语言程序设计教程
Tag:新手,函数,指针,数据类型,对象,Turbo,入门,运算符,数组,结构,二级,,tc,游戏,试题,问答,编译,视频教程

C语言程序:几个经典字符串Hash函数及测试

文章类别:C语言程序设计 | 发表日期:2011-1-17 8:50:42

C语言程序:几个经典字符串Hash函数及测试

1 概述  
链表查找的时间效率为O(N),二分法为log2N,B+ Tree为log2N,但Hash链表查找的时间效率为O(1)。  
设计高效算法往往需要使用Hash链表,常数级的查找速度是任何别的算法无法比拟的,Hash链表的构造和冲突的不同实现方法对效率当然有一定的影响,然而Hash函数是Hash链表最核心的部分,本文尝试分析一些经典软件中使用到的字符串Hash函数在执行效率、离散性、空间利用率等方面的性能问题。  
2 经典字符串Hash函数介绍  
作者阅读过大量经典软件原代码,下面分别介绍几个经典软件中出现的字符串Hash函数。  
2.1 PHP中出现的字符串Hash函数  
static unsigned long hashpjw(char *arKey, unsigned int nKeyLength)  
 
unsigned long h = 0, g;  
char *arEnd=arKey+nKeyLength;  
  
while (arKey < arEnd) {  
h = (h << 4) + *arKey++;  
if ((g = (h & 0xF0000000))) {  
h = h ^ (g >> 24);  
h = h ^ g;  
 
 
return h;  
 
2.2 OpenSSL中出现的字符串Hash函数  
unsigned long lh_strhash(char *str)  
 
int i,l;  
unsigned long ret=0;  
unsigned short *s;  
  
if (str == NULL) return(0);  
l=(strlen(str)+1)/2;  
s=(unsigned short *)str;  
for (i=0; i  
ret^=(s[i]<<(i&0x0f));  
return(ret);  
} */  
  
/* 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)  
 
unsigned long ret=0;  
long n;  
unsigned long v;  
int r;  
  
if ((c == NULL) || (*c == '\0'))  
return(ret);  
/*  
unsigned char b[16];  
MD5(c,strlen©,b);  
return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));   
*/  
  
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_Hash1和OpenSSL_Hash2,至于上面的实现中使用MD5算法的实现函数我们不作测试。2.3 MySql中出现的字符串Hash函数  
#ifndef NEW_HASH_FUNCTION  
  
/* Calc hashvalue for a key */  
  
static uint calc_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);  
 
  
/* Calc hashvalue for a key, case indepenently */  
  
static uint calc_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);  
 
  
#else  
  
/*  
* Fowler/Noll/Vo hash  
 
* 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 function that we've seen so  
* far, and works well on both numbers and strings.  
*/  
  
uint calc_hashnr(const byte *key, uint len)  
 
const byte *end=key+len;  
uint hash;  
for (hash = 0; key < end; key++)  
 
hash *= 16777619;  
hash ^= (uint) *(uchar*) key;  
 
return (hash);  
 
  
uint calc_hashnr_caseup(const byte *key, uint len)  
 
const byte *end=key+len;  
uint hash;  
for (hash = 0; key < end; key++)  
 
hash *= 16777619;  
hash ^= (uint) (uchar) toupper(*key);  
 
return (hash);  
 
  
#endif  
Mysql中对字符串Hash函数还区分了大小写,我们的测试中使用不区分大小写的字符串Hash函数,另外我们将上面的两个函数分别记为MYSQL_Hash1和MYSQL_Hash2。  
2.4 另一个经验字符串Hash函数  
unsigned int hash(char *str)  
 
register unsigned int h;  
register unsigned char *p;  
  
for(h=0, p = (unsigned char *)str; *p ; p++)  
h = 31 * h + *p;  
  
return h;  
 
3 测试及结果  
3.1 测试说明  
从上面给出的经典字符串Hash函数中可以看出,有的涉及到字符串大小敏感问题,我们的测试中只考虑字符串大小写敏感的函数,另外在上面的函数中有的函数需要长度参数,有的不需要长度参数,这对函数本身的效率有一定的影响,我们的测试中将对函数稍微作一点修改,全部使用长度参数,并将函数内部出现的计算长度代码删除。  
我们用来作测试用的Hash链表采用经典的拉链法解决冲突,另外我们采用静态分配桶(Hash链表长度)的方法来构造Hash链表,这主要是为了简化我们的实现,并不影响我们的测试结果。  
测试文本采用单词表,测试过程中从一个输入文件中读取全部不重复单词构造一个Hash表,测试内容分别是函数总调用次数、函数总调用时间、最大拉链长度、平均拉链长度、桶利用率(使用过的桶所占的比率),其中函数总调用次数是指Hash函数被调用的总次数,为了测试出函数执行时间,该值在测试过程中作了一定的放大,函数总调用时间是指Hash函数总的执行时间,最大拉链长度是指使用拉链法构造链表过程中出现的最大拉链长度,平均拉链长度指拉链的平均长度。  
测试过程中使用的机器配置如下:  
PIII600笔记本,128M内存,windows 2000 server操作系统。  
3.2 测试结果  
以下分别是对两个不同文本文件中的全部不重复单词构造Hash链表的测试结果,测试结果中函数调用次数放大了100倍,相应的函数调用时间也放大了100倍。  

从下表可以看出,这些经典软件虽然构造字符串Hash函数的方法不同,但是它们的效率都是不错的.

上一篇:{教程}C语言程序:100,000素数表 人气:2801
下一篇:{教程}如何学好c语言(终极) 人气:2843
视频教程列表
文章教程搜索
 
C语言程序设计推荐教程
C语言程序设计热门教程
看全部视频教程
购买方式/价格
购买视频教程: 咨询客服
tel:15972130058