Algorithm 混合数字和文字标识符的最佳哈希函数

Algorithm 混合数字和文字标识符的最佳哈希函数,algorithm,hash-function,Algorithm,Hash Function,出于性能原因,我需要将一组由字符串标识的对象拆分为组。对象可以由数字或前缀(限定)形式的字符串标识,并用点分隔标识符的各个部分: 12 323 12343 2345233 123123131 ns1:my.label.one ns1:my.label.two ns1:my.label.three ns1:system.text.one ns2:edit.box.grey ns2:edit.box.black ns2:edit.box.mixed 数字标识符从1到数百万。文本标识符很可能有很多以

出于性能原因,我需要将一组由字符串标识的对象拆分为组。对象可以由数字或前缀(限定)形式的字符串标识,并用点分隔标识符的各个部分:

12
323
12343
2345233
123123131
ns1:my.label.one
ns1:my.label.two
ns1:my.label.three
ns1:system.text.one
ns2:edit.box.grey
ns2:edit.box.black
ns2:edit.box.mixed
数字标识符从1到数百万。文本标识符很可能有很多以相同的名称空间前缀(ns1:)和相同的路径前缀(edit.box.)开头

什么是用于此目的的最佳哈希函数?如果我能够基于对象标识符统计数据以某种方式预测bucket的大小,那就太好了。有没有一些好的文章可以基于一些统计信息来构造好的散列函数


有数百万个这样的标识符,但目的是根据哈希函数将它们分成1-2千个组

使用
sha1
并将其截断为您想要的大小可能是安全的


它不会非常有效,但可能哈希函数不会成为瓶颈?

我认为CRC16将是在这些字符串上使用的合理哈希,并且组数不应超过1-2000


这将使哈希表的容量达到1MB+左右,不管其中有多少项*4字节,所以我们说的是50MB,然后还存储了所有实际数据,最好是非常小的数据。

两个好的哈希函数都可以映射到相同的值空间,一般来说,它们的结合不会造成任何新的问题

因此,您的哈希函数可以如下所示:

if it's an integer value:
    return int_hash(integer value)
return string_hash(string value)
除非在模N的某些值周围有任何整数聚集,其中N是可能的桶数,否则
int\u hash
可以只返回其输入

选择字符串散列不是一个新问题。尝试使用“djb2”(djb2)或类似工具,除非您有淫秽的性能要求

我认为修改哈希函数以考虑常见前缀没有多大意义。如果您的散列函数一开始就很好,那么公共前缀不太可能创建任何散列值的聚集

如果您这样做,并且散列没有意外地表现糟糕,并且您将数百万个散列值放入几千个存储桶中,那么存储桶总体将是正态分布的,平均值(几百万/几千)和方差为1/12(几千)^2


平均每个桶有1500个条目,这使得标准偏差大约在430左右。95%的正态分布在平均值的2个标准偏差范围内,因此95%的桶将包含640-2360个条目,除非我的总和做错了。这是否足够,或者是否需要桶的大小更接近?

如果变化仍然太大,请使用两个哈希函数而不是一个,然后将项目放入当前项目较少的容器中。这减少了从O(lgn/lgn)到O(lgn)的变化。@Steve,谢谢你的详细回答。组合哈希函数是一个很好的主意,我一定会重用。我真的不在乎桶的大小是否相似,出于性能原因,我更关心的是最大桶大小不超过1-2000。因此,您认为djb2会很好地分配前缀标识符,对吗?@Keith,我不能将对象放在不同的存储桶中,存储桶应该根据对象标识符进行唯一标识。请注意,95%的存储桶在640-2360范围内的另一面是,2.5%的存储桶将大于2360。如果您的性能要求是“不得超过2000”,那么您的问题与我正在解决的问题不同。djb2将为前缀标识符提供良好的分布,就像它在前缀不存在时提供的一样。实际上,前缀只是更改了散列的“起始值”,因此它不是5381,而是散列(前缀)。您是否考虑过使用以下一个或多个通用散列函数:它们非常快速有效。