什么是英语单词的好哈希函数?

时间:2011-10-08 23:20:10

标签: c++ c hash

我有很多英文单词,我想哈希。什么是良好的散列函数?到目前为止,我的散列函数将字母的ASCII值相加,然后以表格大小为模。我正在寻找一些有效而简单的东西。

4 个答案:

答案 0 :(得分:17)

简单地对字母求和并不是一个好的策略,因为排列会得到相同的结果。

这个(djb2)很受欢迎,可以很好地处理ASCII字符串。

unsigned long hashstring(unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

    while (c = *str++)
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;
}

如果您需要更多替代方案和一些性能指标,请阅读here

已添加:这些是通用哈希函数,其中输入域未提前知道(除了一些非常一般的假设:例如上面的函数与ascii稍微好一点)输入),这是最常见的情况。如果你有一个已知的受限域名(输入固定的组合)你可以做得更好,请参阅Fionn的回答。

答案 1 :(得分:8)

也许这样的事情可以帮到你:http://www.gnu.org/s/gperf/

它为输入域生成优化的散列函数。

答案 2 :(得分:6)

如果你不需要加密安全,我会推荐Murmur Hash。它速度极快,扩散率高。易于使用。

http://en.wikipedia.org/wiki/MurmurHash

http://code.google.com/p/smhasher/wiki/MurmurHash3

如果确实需要加密安全散列,那么我建议通过OpenSSL使用SHA1。

http://www.openssl.org/docs/crypto/sha.html

答案 3 :(得分:2)

有点晚了,但是下面的64位版本的散列函数具有极低的冲突率,并且〜几乎与32位版本一样好:

uint64_t slash_hash(const char *s)
//uint32_t slash_hash(const char *s)
{
    union { uint64_t h; uint8_t u[8]; };
    int i=0; h=strlen(s);
    while (*s) { u[i%8] += *s + i + (*s >> ((h/(i+1)) % 5)); s++; i++; }
    return h; //64-bit
    //return (h+(h>>32)); //32-bit
}

哈希数也非常均匀地分布在可能的范围内,没有我能检测到的聚集 - 这只是使用随机字符串进行检查。
[编辑]
还针对从本地文本文件中提取的单词和LibreOffice词典/词库单词(英语和法语 - 超过97000个单词和结构)进行测试,在64位和1次碰撞中发生0次碰撞在32位:)

(也与相同集合上的FNV1A_Hash_Yorikke,djb2和MurmurHash2相比:Yorikke&amp; djb2表现不佳;在所有测试中,slash_hash的表现略好于MurmurHash2)