唯一的原因是为了避免值聚集到少量桶中(是的,分布)。分布更均匀的哈希表会表现得更加一致。来自
http://srinvis.blogspot.com/2006/07/hash-table-lengths-and-prime-numbers.html
如果假设您的hashCode函数在其他hashCode之间产生以下hashCode {x, 2x, 3x, 4x, 5x, 6x...},那么所有这些都将聚集在仅m个桶中,其中m = table_length/GreatestCommonFactor(table_length, x)。(可以验证/推导出这一点)。现在你可以做以下任一操作以避免聚集:
1. 确保不要生成太多的hashCode是另一个hashCode的倍数,如{x, 2x, 3x, 4x, 5x, 6x...}。但是,如果您的哈希表应该有数百万个条目,则可能会有些困难。
2. 或者通过使GreatestCommonFactor(table_length, x)等于1,即通过使table_length与x互质,使m等于table_length。如果x可以是任何数字,那么请确保table_length是质数。
更新:(来自原答案作者)
这个答案对于哈希表的常见实现是正确的,包括Java实现的原始Hashtable以及.NET的当前Dictionary实现。
但是,关于Java的HashMap
,容量应该是质数的答案和假设都是不准确的。实现HashMap
的方式非常不同,它利用大小为2的幂的表来存储桶,并使用n-1& hash
来计算要使用哪个桶,而不是传统的hash%n
公式。
Java的HashMap
会强制将实际使用的容量设置为请求容量上面最接近的下一个大于等于2的幂。
对比Hashtable
:
int index = (hash & 0x7FFFFFFF) % tab.length
https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/classes/java/util/Hashtable.java#L364
转换为 HashMap
:
first = tab[(n - 1) & hash]
https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/classes/java/util/HashMap.java#L569