您的位置:首页 > 其它

Hash算法的使用

2016-06-17 10:49 190 查看


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。

 

最后借用一个前辈的说法“算法的力量很强”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: