Java:一个“质数”还是一个“2的幂”作为HashMap的大小?

ztyzrc3y  于 2023-01-07  发布在  Java
关注(0)|答案(5)|浏览(147)

很多书和教程都说,哈希表的大小必须是质数,才能在所有桶中均匀分布键。但是Java的HashMap总是使用2的幂。它不应该使用质数吗?“质数”还是“2的幂”作为哈希表的大小,哪个更好?

x8diyxa7

x8diyxa71#

使用2的幂有效地屏蔽了散列代码的高位,因此质量差的散列函数在这种情况下可能表现得特别糟糕。
Java的HashMap通过不信任对象的hashCode()实现并对其结果应用第二级散列来缓解这一问题:
将补充哈希函数应用于给定的hashCode,以防止哈希函数质量差。这一点非常重要,因为HashMap使用2的幂长度哈希表,否则会遇到低位相同的hashCode冲突。
如果你有一个很好的散列函数,或者做一些类似于HashMap的事情,那么你是否使用质数等作为表的大小就没有关系了。
另一方面,如果散列函数是未知的或者质量很差,那么使用素数可能是更安全的选择,但是这会使动态大小的表更难实现,因为突然之间你需要能够产生素数,而不仅仅是将大小乘以一个常数。

5kgi1eie

5kgi1eie2#

标准的HashMap实现有一个hash方法,它可以重新散列对象的散列代码以避免这个陷阱,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.
 */
bpsygsoo

bpsygsoo3#

要知道质数和2的幂哪个更好,唯一的方法就是对其进行基准测试。
很多年前,当我编写一个性能严重依赖于符号表查找的汇编程序时,我使用了一大块生成的标识符进行了测试。即使使用简单的Map,我也发现2的幂,正如预期的那样,比同样大小的质数个桶具有更少的均匀分布和更长的链。它仍然运行得更快,因为通过位屏蔽选择桶的速度更快。
我强烈怀疑java.util的开发者不会求助于额外的散列和2的幂,除非用质数个bucket作为基准,这是设计散列数据结构时很明显要做的事情。
出于这个原因,我确信rehash和2的幂大小比质数个bucket为典型的Java散列Map提供了更好的性能。

mpgws1up

mpgws1up4#

从性能/计算时间的观点来看,可以仅利用位屏蔽来计算2的幂大小,这比否则将需要的整数模运算快。

2vuwiymt

2vuwiymt5#

如果你使用quadratic probing来解决冲突,你可能应该使用质数大小的哈希表。如果你有一个质数大小的表,二次探测将命中一半的条目,如果它不是质数,命中的条目会更少。所以即使你的哈希表还不到一半满,你也可能找不到合适的地方来存储条目。由于Java哈希Map不使用二次探测,所以没有必要使用质数作为大小。

相关问题