【问题标题】:Using hash as a bucket index, modulo vs bit-mask使用哈希作为存储桶索引,模与位掩码
【发布时间】:2015-02-10 14:45:52
【问题描述】:

我一直在研究哈希表,其中一些数据经过哈希处理并用于存储桶索引。

一些库使用散列与桶大小的模数,而其他库使用位掩码。 仅使用桶掩码使用的位(确保不超出范围)。

位掩码:

index = h->hash_func(key) & h->hash_mask;

模数:

index = h->hash_func(key) % h->bucket_tot;

虽然两者之间存在明显差异,例如位掩码的存储桶大小限制,但确保散列在较低位上提供良好分布、模数速度……等。

是否有充分的理由选择一个而不是另一个?


(我可能会为自己的用例尝试和基准测试,但很好奇关于此事的已知信息)。

请注意,这仅用于 key:value 存储、(字典/哈希/关联数组)和安全相关。

使用位掩码实现动态调整大小、链接哈希表的示例:

使用模数的示例:

【问题讨论】:

  • 与其提出笼统和模糊的问题并抱怨答案,也许更有建设性的方法是用您希望看到的答复来回答您自己的问题。

标签: hashtable associative-array


【解决方案1】:

您提到了“桶”索引,所以我假设您的意思是具有单独链接的哈希表作为冲突解决方案,在这种情况下,没有理由使用您提到的模数或位掩码“更强”(顺便说一句,这并不那么明显,因为你说)。

在某些语言中,尤其是基于 Java/JVM 的语言中,数组索引是有符号的 32 位整数,因此位掩码的最大数组大小为 2^30,这可能是不够的,也是使用 no-power 的充分理由-of-two 表大小和模数,您可以非常接近地接近 2^31-1(最大可能有符号 32 位整数)。但是由于您使用的是 C++ 语法,因此您不必担心。

另外,如果你的意思不仅仅是单独的链接,一些开放寻址冲突解决算法需要表大小满足某些条件,例如,如果你实现双散列,表大小应该是素数。在这种情况下,您显然应该只使用模数来获取表中的初始索引。

【讨论】:

  • 嗯,桶数组的最大大小只是一方面。我认为有充分的理由选择一个而不是另一个。 Glib 是一个相当受欢迎的理由。也许我需要问作者,但我很想回答“Glib 选择使用位掩码来获取存储桶索引,因为 '___'”
  • @ideasman42 简短回答 - 因为它更快。这就是您所说的“模数速度”。
  • 对,但还有其他权衡。可能最好我只是使用位掩码进行测试,看看它是如何执行的,因为在这种情况下似乎知道真正的 best 选择。
【解决方案2】:

这也不仅仅与性能有关,有时还与您的问题所在的领域有关。例如,您可能有一个希望散列负数的掩码。使用模数,您必须编写特殊情况来处理它们,而不是使用位掩码。

【讨论】:

  • 在我见过的所有使用模数的情况下,哈希都是无符号整数,即使在有符号的情况下,您也可以简单地转换为无符号值 - 它不会在 C/C++ 中增加任何开销例如。
  • 在您所看到的问题域中,哈希使用了无符号整数。但是,例如在实现 Perlin 噪声时,该函数包含从 -1 到 1 的有效范围。在这种情况下,使用模数只需要一些额外的工作。我不是说一个比另一个好,而是回答最初的问题,为什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多