【发布时间】:2011-12-03 18:20:48
【问题描述】:
我有一长串英语单词,我想对它们进行哈希处理。什么是好的散列函数?到目前为止,我的散列函数将字母的 ASCII 值相加,然后对表格大小取模。我正在寻找高效且简单的东西。
【问题讨论】:
-
可以在其他 stackexchange 网站上找到这个问题的好答案:softwareengineering.stackexchange.com/questions/49550/…
我有一长串英语单词,我想对它们进行哈希处理。什么是好的散列函数?到目前为止,我的散列函数将字母的 ASCII 值相加,然后对表格大小取模。我正在寻找高效且简单的东西。
【问题讨论】:
简单地将字母相加并不是一个好的策略,因为排列会产生相同的结果。
这个 (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。
如果您需要更多替代方案和一些性能指标,请阅读here。
补充:这些是一般散列函数,其中输入域是事先不知道的(除了一些非常一般的假设:例如,上面的内容与 ascii 一起工作得更好一些输入),这是最常见的情况。如果您有一个已知的受限域(固定输入集),您可以做得更好,请参阅 Fionn 的回答。
【讨论】:
unsigned long值。由您来操作散列以适应您的约束。
也许这样的事情会帮助你:http://www.gnu.org/s/gperf/
它为输入域生成一个优化的散列函数。
【讨论】:
如果您不需要加密安全,我建议使用 Murmur Hash。它速度极快,并且具有很高的扩散性。易于使用。
http://en.wikipedia.org/wiki/MurmurHash
http://code.google.com/p/smhasher/wiki/MurmurHash3
如果您确实需要加密安全哈希,那么我建议通过 OpenSSL 进行 SHA1。
【讨论】:
有点晚了,但这里有一个哈希函数,对于下面的 64 位版本,冲突率极低,并且 ~ 几乎 ~ 对 32 位版本同样好:
uint64_t slash_hash(const char *s)
//uint32_t slash_hash(const char *s)
{
union { uint64_t h; uint8_t u[8]; } uu;
int i=0; uu.h=strlen(s);
while (*s) { uu.u[i%8] += *s + i + (*s >> ((uu.h/(i+1)) % 5)); s++; i++; }
return uu.h; //64-bit
//return (uu.h+(uu.h>>32)); //32-bit
}
哈希数也非常均匀地分布在可能的范围内,没有我可以检测到的聚集 - 这仅使用随机字符串进行检查。
[编辑]
还针对从本地文本文件中提取的单词以及 LibreOffice 词典/同义词库单词(英语和法语 - 超过 97000 个单词和结构)进行了测试,在 64 位中出现 0 次冲突,在 32 位中出现 1 次冲突-位:)
(还与 FNV1A_Hash_Yorikke、djb2 和 MurmurHash2 在同一组上进行比较:Yorikke 和 djb2 表现不佳;slash_hash 在所有测试中都略好于 MurmurHash2)
【讨论】:
union { uint64_t h; uint8_t u[8]; } uu; 和代码中的类似更改 -->> uu.h=strlen(s); ... uu.u[i%8] += ... 等