集群整数的散列函数

时间:2015-11-12 21:19:07

标签: c++ hash

我正在尝试设置一个哈希表(在C ++中,使用unordered_map容器),它包含1875个整数项,这些项在0到4891区间内随机分布。现在我的问题是这个区间内的分布是不统一而是看起来像这样: enter image description here

其中每个1875个随机整数被绘制为一个点,x对应于整数值,y = 1(以便可视化分布)。

显然,分布是这样的,即在没有随机整数的情况下存在很大的差距。如果我使用身份函数作为我的哈希函数(即使用随机整数本身作为哈希值),我得到714个空桶,814个带有单个元素的桶,带有2个元素的499个桶和带有3个或更多元素的21个桶。 / p>

我正在使用英特尔C ++编译器,它使用2的幂来表示哈希表中的桶数。在我的情况下,哈希表现在有2 ^ 11 = 2048个桶。

对于这种情况,什么是好的哈希函数?我的理解是,在这种情况下,一个好的哈希函数将摆脱这些聚簇整数并在更均匀的分布中将它们混乱,但是如何实现呢?

3 个答案:

答案 0 :(得分:1)

我发现Pearson的Hash函数是获得随机性的绝佳方法:

https://en.wikipedia.org/wiki/Pearson_hashing

基本上,这个想法是它默认会在一个256个bin的数组中生成一堆非常随机的数字,但是你可以将它修改为1800 为你的情景。重要的是阵列足够小以适应内存。

答案 1 :(得分:1)

如果您需要减少冲突次数,可能有助于查看专门的哈希方案,如cuckoo hashing。基本上,您可以分摊多个哈希函数以保持O(1)复杂性。

如果碰撞成本低廉(例如它们适合缓存线或它们是可预测的),无论碰撞的渐近成本如何,您仍然可能会看到更好的性能。

由于具有良好的缓存特性,因此倾向于使用扁平结构。当性能很重要时,这也是他们倾向于首选的原因之一。

答案 2 :(得分:0)

所以我花了一些时间尝试不同的事情。以下是我的结论。

首先,必须意识到将1875个元素拟合到具有2048个桶的哈希表中可能会产生相当多的冲突。实际上,如果考虑到每个元素具有被分配给2048个桶中的任何一个的相等概率,则预期的冲突数是646(通过类似于所谓的生日问题的参数,参见https://math.stackexchange.com/questions/35791/birthday-problem-expected-number-of-collisions?rq=1,公式是预期的碰撞数nb = n - N *(1 - (1 - 1 / N)^ n)其中n是元素数,N是桶数。例如,如果1875个元素是在[0,2047]间隔中随机选择的,允许重复,或者1875个元素是在相对于数字的非常大的间隔内随机选择的桶2048 有或没有重复

考虑到这一点,使用身份函数获得的541碰撞作为哈希函数(参见原始问题)似乎并不太糟糕。碰撞次数小于均匀分布情况的原因尽管分布中存在较大的间隙,但由于问题的性质,1875个元素具有不同的值,因此只有大于2048的元素才会导致碰撞,因为它们是使用模运算符缠绕。

现在,我们知道一个哈希函数将我们的输入区间[0,4891]映射到更大的区间(例如32位整数),这是不可取的,因为它会导致比身份更多的冲突哈希函数。然而,人们可能想知道是否有可能从输入区间[0,4891]到一些不太大的区间(可能是相同的[0,4891]区间或任何其他区间,如[0]进行随机和统一的映射。 ,2048],[0,5000]等),这将减少碰撞。我按照rts1的建议尝试了类似Pearson的映射,但发现它没有改善碰撞次数。

到目前为止,我已经决定使用的是简单的身份函数作为哈希函数,并确保我的元素数量不太接近我的桶数(1.5倍的元素数量似乎非常合理桶的数量。)