java 散列函数中,选择 31 作为乘数,为何?

散列函数中,选择 31 作为乘数

@Override
public int hashCode() {
int result = 17;
result = 31 * result + x;
result = 31 * result + y;
result = 31 * result + z;
return result;
}
理想的散列函数应当具有均匀性,即不相等的对象应当均匀分布到所有可能的散列值上。这就要求了散列函数要把所有域的值都考虑进来,可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。
上述的散列函数中, 为什么选择31作为乘数, 又为什么用31就不会丢失信息?

在上述的散列函数中,选择 31 作为乘数有几个原因:

  1. 31 是一个素数。使用素数作为乘数有助于生成更均匀的哈希值分布。如果使用一个合数作为乘数,特别是较小的合数,那么哈希值可能会更容易出现碰撞,因为生成的哈希值可能在某些模式下重叠。
  2. 31 是一个奇数。使用奇数作为乘数可以减少信息丢失的风险。如果使用偶数作为乘数,那么在发生乘法溢出时,信息可能会丢失,因为乘以 2 相当于向左移一位。使用奇数作为乘数可以避免这个问题。
  3. 31 的乘法可以优化。对于许多计算机系统,乘法运算相对较慢。然而,乘以 31 可以通过位操作进行优化。例如,对于一个整数 n,计算 n * 31 可以表示为 (n << 5) - n,即将 n 左移 5 位后再减去 n。这种位操作通常比直接进行乘法运算更快。

关于为什么使用 31 不会丢失信息,这实际上是因为 31 是一个奇数。正如前面提到的,当使用偶数作为乘数时,乘法溢出可能导致信息丢失,因为乘以 2 相当于向左移一位。然而,当使用奇数作为乘数时,乘法溢出的影响相对较小,因为奇数乘法不会导致最低位的信息丢失。

总之,选择 31 作为哈希函数中的乘数有助于生成均匀分布的哈希值,并降低信息丢失的风险。同时,31 的乘法还可以通过位操作进行优化,提高计算效率。

奇数乘法不会导致最低位的信息丢失

让我们通过一个二进制数的例子来解释这一点。

假设我们有一个 8 位二进制数 0101 1010(十进制表示为 90)。

当我们将这个数乘以 2(即左移一位)时,我们得到 1011 0100(十进制表示为 180)。注意到,原始数字的最低位(最右边的一位)是 0,乘以 2 之后,这个信息被丢失了。原始数字和结果数字之间的关系仅仅是左移了一位,最低位的信息没有保留。

现在,让我们将原始数字乘以一个奇数,比如 3(二进制表示为 11):


0101 1010 (90)
x      0011 (3)
----------
  0101 1010
 0101 1010
----------
 1111 0110 (270)

可以看到,乘以奇数后的结果是 1111 0110(十进制表示为 270)。在这个例子中,尽管可能会出现溢出(如果我们仅使用 8 位存储结果),但是我们仍然保留了原始数字的最低位信息(0)。这是因为奇数乘法不会导致最低位的信息丢失。

综上所述,当使用偶数作为乘数时,乘法溢出可能导致信息丢失,因为乘以 2 相当于向左移一位。然而,当使用奇数作为乘数时,乘法溢出的影响相对较小,因为奇数乘法不会导致最低位的信息丢失。

为什么要保证 最低位的信息不丢失

保留最低位信息有助于维护原始数据的一部分特征,从而在哈希计算中保持更好的分布。当我们在哈希函数中使用奇数乘数时,可以避免因为乘法溢出而导致的最低位信息丢失,从而使得哈希函数生成的哈希值具有较好的随机性和分布。

为什么随机性和分布很重要呢?在哈希表(如 HashMapHashSet)中,哈希值的分布决定了它们的性能。理想情况下,我们希望不同的对象能够产生尽可能不同的哈希值,以减少哈希冲突。当哈希冲突较少时,哈希表的查找、插入和删除操作的性能更高。

当我们使用偶数乘数时,如果发生溢出,最低位信息可能会丢失。这意味着某些原始数据的特征可能会丢失,从而导致生成的哈希值在分布上出现规律性。这可能会增加哈希冲突,从而降低哈希表的性能。

然而,当我们使用奇数乘数时,由于最低位信息得以保留,哈希函数生成的哈希值具有更好的随机性和分布。这有助于减少哈希冲突,提高哈希表的性能。

总之,保留最低位信息可以帮助维持哈希值的随机性和分布,从而提高哈希表的性能。在哈希函数中使用奇数乘数,可以避免因为乘法溢出而导致的最低位信息丢失。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值