许多书籍和教程说,一个哈希表的大小必须是素数在所有的桶均匀分布键。 但是Java的HashMap
始终使用一个大小为二的幂。 它不应该被使用的黄金? 更棒的是,一个“素”或“两权”作为哈希表的大小?
Answer 1:
使用两种有效地屏蔽了哈希码的顶部位的动力。 因此,一个劣质的散列函数可能在这种情况下尤其表现不佳。
Java的HashMap
通过不信任对象的缓解此hashCode()
的实施和应用散列其结果的第二层次 :
适用补充哈希函数在给定的hashCode,其抵御质量差的散列函数。 这是至关重要的,因为使用HashMap的功率的两长度哈希表,否则会遇到碰撞用于不在较低位不同散列码。
如果你有一个好的哈希函数,或者做类似的事如何HashMap
呢,也无所谓是否使用质数等作为表的大小。
如果,另一方面,散列函数是未知的或质量差,然后使用一个素数将是一个更安全的赌注。 它将,然而,使动态调整大小的表格技巧就实现,因为突然的,你需要能够生产,而不是仅仅由一个常数因子乘以大小质数。
Answer 2:
该标准的HashMap实现有一个hash
这老调重弹的对象的hashCode避免陷阱的方法。 前面的评论的hash()
方法如下:
/**
* 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.
*/
Answer 3:
知道哪些是素数,电源的两间更好的唯一方法就是对它进行基准测试。
很多年前,写一个汇编程序,其性能上的符号talbe查找强烈地依赖时,我测试了使用生成的标识符的一大块。 即使有一个天真的映射,我发现,电源的二,符合市场预期,有较少均匀分布和长链比斗的类似规模的素数。 它仍然跑得更快了,因为斗选择由位掩码的速度。
我强烈怀疑的java.util开发商不会使出了额外的散列和功率的二没有标杆就不要使用桶的质数。 这是设计一个散列数据结构时做的一个非常明显的事情。
出于这个原因,我敢肯定的翻版和功率的二尺寸给出了典型的Java哈希映射比桶的质数更好的性能。
Answer 4:
从幂的两种尺寸可以只用位屏蔽,比这将被另外要求整数除法更快来计算的视性能/计算时间点。
Answer 5:
您如果使用可能应该用黄金尺寸的哈希表二次探测的冲突解决。 如果你有一个黄金尺寸表,二次探测将达到一半的条目,少,如果它不是一个素数。 所以,即使你的哈希表少于半满的,你可能无法找到一个合适的地方来存储条目。 由于Java的哈希映射不使用二次探测,也没有必要使用素数的大小。