字符串哈希函数

参见:http://www.cnblogs.com/uvsjoh/archive/2012/03/27/2420120.html

函数太多了,如上述文章中所述,BKDRHash算法在实现方便且表现出色,摘录其C的实现

 1 unsigned int BKDRHash(char *str)
 2 {
 3     unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
 4     unsigned int hash = 0;
 5  
 6     while (*str)
 7     {
 8         hash = hash * seed + (*str++);
 9     }
10  
11     return (hash & 0x7FFFFFFF);
12 }

其中第8行需要注意,这里在计算过程中也许会产生溢出,因为使用了unsigned int类型,相当于做了一次取模操作(hash % (0xFFFFFFFF + 1)=2^32,或者说是hash & 0xFFFFFFFF),在返回时又对hash进行了一次取模,这次采用的是(0x7FFFFFFFF + 1)=2^31。虽然两次取模使用的参数不同,但是因为前置是后者的倍数关系,中间的溢出对最后结果没有影响。

 

在同一个程序中全部使用这样一个函数是没有问题的,但是当涉及到不用语言之间的交互时情况就有所不同了。下面给出一个python版本的上述代码翻译实现:

def BKDRHash(string):
    seed = 131
    hash = 0
    for ch in string:
        hash = hash * seed + ord(ch)
    return hash & 0x7FFFFFFF

由于python中整数类型可以很长很长(是不是无限?)所以在中间步骤计算hash值时其值不像C版本中的那样会溢出,而是会原样存储,因此以上python程序和c版本的是等价的(最好还是对每次hash结果进行一次hash & 0x7FFF FFFF)。

 

之所以要给出python版本的程序是因为今天在实现一小游戏功能:服务器给出一个答案和待选字符,用户在指定时间内输入该答案(从待选字符中)

比如服务器给出ans:hello, word: a b c d h e l o x y z,唯有当用户拼出hello时才算正确,这其实和网页验证码有些类似。我们不想给客户端明文答案,而是一个答案的hash值即hash(ans),通过比较hash(用户输入)和hash(ans)就可以判断对错,同时避免了给出明文答案。于是用python实现了服务端的bkdr hash函数,同时在客户端也实现了javascript版本的brdr hash函数如下:

// bug exists!
var string_hash = function(str, seed) {
    var seed = !!seed ? seed : 131;
    var hash = 0;
    var i = 0;
    while (true) {
        var ch = str.charCodeAt(i++);
        if (!(ch > 0 || ch < 0)) {
            break;
        }
        hash = seed * hash + ch;
    }
    return hash & 0x7FFFFFFF;
};

结果测试发现同个字符串python和javascript实现给出的hash值不一致,原来javascript中的数字内部都是以64位浮点形式存储,最多只能保留52位左右的整数精度,因此当javascript版本在计算hash值时,hash值会出现精度丢失,这个和C语言中unsigned int类型溢出不同,它仍然是一个浮点表示的数,但不会出现折回,也就没有取模的效果了,导致最后结果错误。既然最后要取模,那么在中间阶段就开始取模,可以避免出现数值过大时的精度丢失。如下:

var string_hash = function(str, seed) {
    var seed = !!seed ? seed : 131;
    var hash = 0;
    var i = 0;
    while (true) {
        var ch = str.charCodeAt(i++);
        if (!(ch > 0 || ch < 0)) {
            break;
        }
        hash = (seed * hash + ch) & 0x7FFFFFFF;
    }
    return hash;
};

 感觉各种语言交叉着用,有时候真是会不知不觉掉进坑里

posted @ 2014-10-17 08:52  卖程序的小歪  阅读(2339)  评论(0编辑  收藏  举报