Hash算法的使用

来源:互联网 发布:淘宝怎么取消匿名 编辑:程序博客网 时间:2024/06/01 08:47

Hash算法的使用

标签: 默认分类 | 发表时间:2011-08-06 06:35 | 作者:GliderX khsing
分享到:
出处:http://hi.baidu.com/gliderx

在对语料文本进行2,3元切分时,需要借助hash表来获得切分内容在内存中的位置,以便能够记录语料库中出现的次数。以前知道有很多hash算法,但没认真研究过,今天才知道hash算法差距还是很明显的。

首先我选择的是暴雪在魔兽里的hash算法,这个算法很高级,是time33类型的一个变种(有关time33的介绍,可以参考:http://www.cnblogs.com/napoleon_liu/articles/1911571.html),而且很巧妙的借助3次hash避免字符串比较这种费时的操作,并且不用链表来存储冲突,3次hash冲突值能相等的可能行只有1/10的23次方,应该说不可能冲突了。具体算法请参考:http://blog.csdn.net/eaglewood2005/article/details/4394583。

但很遗憾,这种算法对于一个文本有数百万条记录的情况处理不够理想。首先,预先分配的Table数量是有限的,我分配0x3ffffff大小,再大就很容易分配失败了。其次,正是由于他不用链表处理冲突,当越来越多的加入进来时,处理冲突地方就需要不断往下轮询空余的Table下标,当积累到一定的时候,大概是200万条记录的时候,效率就开始急剧下降,降将到我无法接受,进度条很久都不会动,最后没耐心等下去了。

 

第二个选择的算法是一个很常见的OpenSSL里的算法

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<l; i++)
        ret^=(s[i]<<(i&0x0f));
    return(ret);
}

很简单吧,不过这个算法也仅在一个数量范围内比较好用,对于大记录的hash效果不好,我对328万条记录的结果,bucket利用率仅仅只有 2.14%,最大的冲突长度高达147。 其实这个算法也让程序在20分钟内统计完成。

 

不过感觉2.14%的利用率实在太低,有必要选择一个更好的算法。于是找到了php的hash算法,这个zend公司的算法也是time33的一种,而且有独到的地方,比如他的hash值不是从0开始,而是从5381开始,5381这个数字有什么意义呢?

Magic Constant 5381:
  1. odd number
  2. prime number 
  3. deficient number
  4. 001/010/100/000/101 b

算法我就不列了,大家可以很容易找到。这个算法非常有效,程序运行速度翻倍,只要10分钟就可以统计好一个4GB的语料库,而且更加惊人的是在相同的测试条件下,他的bucket利用率高达33.16%,最大冲突长度只有14。

 

最后借用一个前辈的说法“算法的力量很强”。

0 0
原创粉丝点击