Java 爪哇:A";素数;数字或“a”;“二的力量”;作为HashMap大小?

Java 爪哇:A";素数;数字或“a”;“二的力量”;作为HashMap大小?,java,hash,hashmap,hashtable,hashcode,Java,Hash,Hashmap,Hashtable,Hashcode,许多书籍和教程都说,哈希表的大小必须是一个素数,才能在所有存储桶中均匀分布键。但是Java的HashMap总是使用2的幂的大小。它不应该使用素数吗?更好的方法是,将“素数”或“二的幂”作为哈希表大小?使用二的幂有效地屏蔽了哈希代码的顶部位。因此,在这种情况下,低质量的散列函数的性能可能会特别差 Java的HashMap通过不信任对象的hashCode()实现和: 将补充哈希函数应用于给定的哈希代码,以防止出现低质量的哈希函数。这是至关重要的,因为HashMap使用两个长度哈希表的幂,否则会遇到低

许多书籍和教程都说,哈希表的大小必须是一个素数,才能在所有存储桶中均匀分布键。但是Java的HashMap总是使用2的幂的大小。它不应该使用素数吗?更好的方法是,将“素数”或“二的幂”作为哈希表大小?

使用二的幂有效地屏蔽了哈希代码的顶部位。因此,在这种情况下,低质量的散列函数的性能可能会特别差

Java的
HashMap
通过不信任对象的
hashCode()
实现和:

将补充哈希函数应用于给定的哈希代码,以防止出现低质量的哈希函数。这是至关重要的,因为HashMap使用两个长度哈希表的幂,否则会遇到低位不不同的哈希代码冲突

如果您有一个好的哈希函数,或者执行类似于
HashMap
的操作,那么是否使用素数等作为表大小并不重要


另一方面,如果哈希函数未知或质量差,那么使用素数将是更安全的选择。然而,它会使动态大小的表变得很难实现,因为突然之间你需要能够产生素数,而不是仅仅将大小乘以常数因子。

标准HashMap实现有一个
hash
方法,它会重新生成对象的hashcode以避免这个陷阱。前面的评论是:


从性能/计算时间的角度来看,两种大小的功率可以仅使用位掩蔽来计算,这比否则需要的整数除法要快

知道素数和二的幂之间哪一个更好的唯一方法是对它进行基准测试

许多年前,当编写一个性能强烈依赖于符号talbe查找的汇编程序时,我使用一大块生成的标识符对此进行了测试。即使使用一个简单的映射,我发现二的幂,正如预期的那样,比一个大小相似的素数桶有更少的均匀分布和更长的链。由于位掩蔽选择存储桶的速度,它仍然运行得更快

我强烈怀疑java.util开发人员如果不使用素数bucket对其进行基准测试,就不会求助于额外的哈希和2的强大功能。在设计散列数据结构时,这是一件非常明显的事情


出于这个原因,我确信两个大小的重哈希和幂次对于典型的Java哈希映射比素数个存储桶提供更好的性能。

如果用于冲突解决,您可能应该使用素数大小的哈希表。如果您有一个素数大小的表,二次探测将命中一半的条目,如果它不是素数,则命中较少。因此,即使哈希表不足一半,您也可能找不到合适的位置来存储条目。由于Java哈希映射不使用二次探测,因此不需要使用素数作为大小。

出于好奇:为什么?(或者你有没有参考/链接来解释这一点)?你确定表的大小无关紧要吗?好的散列函数不是为了减少冲突的数量而将数据分散到整个表中吗?但是,如果表非常小,那么冲突将增加,而不考虑哈希函数。我错过了什么吗?@小册子:很明显,越大越好(或者至少不太可能越差)。但是,对于类似的大小,没有理由选择素数等,只要哈希函数是高质量的。@小册子:我重新编写了答案的这一部分,因为它不太清楚我的意思。@小册子当超过负载因子时,表的容量会增加(大约增加两倍),因此,即使表的初始容量非常小,表也会扩展到适合包含的最大条目数的大小。一个好的初始猜测意味着随着表的增长而减少大小调整,但一个坏的初始猜测最终还是会产生一个有效的表。我怀疑他们是否真的这么说,如果他们这么做了,那他们就错了。HashMap(他们称之为Dictionary)的NET实现使用一个素数硬编码列表来表示bucket大小。所以,我不太确定rehash与Prime的优势,至少我不会将这个结论推广到其他平台。
/**
 * Retrieve object hash code and applies a supplemental hash function to the
 * result hash, which defends against poor quality hash functions.  This is
 * critical because HashMap uses power-of-two length hash tables, that
 * otherwise encounter collisions for hashCodes that do not differ
 * in lower bits. Note: Null keys always map to hash 0, thus index 0.
 */