为什么将HashTable的长度设置为素数是一个好习惯?

时间:2011-03-01 08:27:55

标签: c# arrays hashcode primes

当我点击这段时,我正在浏览Eric Lippert的Guidelines and rules for GetHashCode最新博客文章:

  

我们在这里可能更聪明;就像List在它满了时调整自身大小一样,bucket set也可以自己调整大小,以确保平均bucket长度保持低位。此外,由于技术原因,将桶设置长度设置为主要数字通常是一个好主意,而不是100.我们可以对此哈希表进行大量改进。但是这个哈希表的简单实现的快速草图现在可以做到。我想保持简单。

所以看起来我错过了一些东西。为什么将它设置为素数是一个好习惯?

3 个答案:

答案 0 :(得分:16)

你可以找到那些暗示光谱两个相反端的人。另一方面,为哈希表的大小选择素数将减少冲突的可能性,即使哈希函数不太有效地分配结果。请注意,如果(在最简单的例子中争论)确定2个大小的幂,则只有较低位影响存储区,而对于素数,将使用散列结果中的大多数位。

另一方面,您可以通过选择更好的散列函数,甚至通过应用一些位操作来重新散列散列函数的结果,并使用2散列大小的幂来加速计算,从而获得更多收益。

作为现实生活中的一个例子,Java HashTable最初是通过使用素数(或接近素数)来实现的,但是从Java 1.4开始,设计被改为使用两个桶的功率并添加了第二个快速哈希函数应用于初始哈希的结果。可以找到一篇评论该变化的有趣文章here

基本上是这样的:

  • 即使在不太好的哈希函数的情况下,素数也有助于将输入分散到不同的桶中。

  • 通过对哈希函数的结果进行后处理,并使用2大小的幂来加速模运算(位掩码)并补偿后处理,可以实现类似的效果。

答案 1 :(得分:15)

因为这会产生更好的散列函数并减少可能的碰撞次数。这在Choosing a good hashing function

中有解释
  

基本要求是   功能应该提供统一   散列值的分布。一个   非均匀分布增加了   碰撞次数和费用   解决它们。

     

分配需要统一   仅适用于出现的表格大小   应用程序。特别是,如果一个   使用精确的动态调整大小   哈希的加倍和减半   功能只有在需要时才是统一的   s是2的幂。在另一   手,一些哈希算法提供   只有当s是素数时才会出现均匀哈希   号。

答案 2 :(得分:9)

假设您的铲斗组长度是2的幂 - 这使得mod计算速度非常快。这也意味着桶选择仅由哈希码的前m位确定。 (其中m = 32 - n,其中n是使用2的幂。所以就像你立即丢弃哈希码的有用位一样。

或者像2006年的this blog post所说:

  

假设你的hashCode函数导致以下hashCodes {x,2x,3x,4x,5x,6x ...},那么所有这些都将聚集在m个桶中,其中m = table_length / GreatestCommonFactor(table_length,x)。 (验证/得出这个是微不足道的)。现在,您可以执行以下操作之一以避免群集:

...

  

或者通过使GreatestCommonFactor(table_length,x)等于1来简单地使m等于table_length,即通过使table_length与x进行互操作。如果x可以是任何数字,那么请确保table_length是素数。