【问题标题】:How to allow hashing functions returning 64 bit integers for a HashSet如何允许散列函数为 HashSet 返回 64 位整数
【发布时间】:2018-01-23 00:41:40
【问题描述】:

我有一个 4 维 Point 类,其中 4 个值中的每一个都是介于 0 到大约 1000 之间的整数,因此此类 Point 上的散列函数将返回从 0 到 1000^4 的值,因此需要 40 位如果我的数学是正确的。但是,我必须重写的 GetHashCode 方法(散列函数)只能返回 32 位整数; 40 位整数还不够。

我的最终目标是使用 HashSet 来检查列表中重复的 4D 点,方法是遍历所有这些点并将它们添加到 HashSet(如果该索引处已经有一个元素,则该点已经被看到并且是重复的)。 这意味着哈希集中的索引与哈希点的值一样多,即 1000^4 个不同的索引。

将放入哈希集中的实际点数最多为 8,000。每次尝试将一个点插入哈希集中时,预计会发生 0 或 1 次冲突(再也不会发生)。

请原谅我可能对 HashSets 的误解。我对我的算法的运行时间不太在意,但我正在尝试看看它的“大哦”时间成本会有多低。

【问题讨论】:

  • HashSet 要求您使用 32 位散列。对于具有相同哈希的不相等集合元素,它没有任何问题。一个明显的实现是 return v1 ^ (v2
  • 请记住,哈希函数的设计目的是减少冲突,而不是完全消除冲突。有远远超过 40 亿个短字符串,但不知何故,字符串哈希表在 32 位哈希上就可以了。这是因为碰撞非常罕见。散列不能代替相等检查;相反,它加快了相等性检查,因为您只需对冲突进行完全相等性检查
  • @EricLippert 虽然我认为它会从 O(1) 移动到 O(n),但我只是希望从 32 位到 40 位的轻微增加仍然会有一些 O(1 ) 解决方案。
  • @TeeMee123 这是 O(n),其中 n 是每个对象的平均碰撞次数,而不是*集合的大小。在您的情况下,每个对象的平均碰撞次数几乎可以肯定是一个常数,并且是一个非常小的常数,这使得哈希集在实践中具有 O(1) 操作。
  • 这是一个与您提出的问题完全不同的问题。在 SO 上,我们称之为“XY 问题”。你对如何解决你的问题有一些完全疯狂的想法,然后你就这个疯狂的想法提出问题,导致每个人都说“这太疯狂了”。如果您的问题是“我如何为四个小整数的向量制作分布良好的哈希码”,那么问这个问题

标签: c# hash hashset


【解决方案1】:

如果您覆盖Equals,则HashSet 仍将确保唯一性。散列本质上是一种优化,因此它不必比较集合中的每个元素。

除非您对程序的运行速度有具体要求,否则您应该可以使用这样的简单 GetHashCode 实现:

int GetHashCode()
{
  return Tuple.create(this.a, this.b, this.c, this.d).GetHashCode();
}

如果您已经尝试过,但仍然不够(或者您这样做是为了好玩),那么您可以尝试使用 long 实现自己的哈希集。

【讨论】:

    【解决方案2】:

    你有 2^64 的内存吗?哈希码应该将对象映射到一个足够小以适合内存的数组。 (HashSet 将进一步减少哈希中的位数,因此)

    只需返回一个 32 位哈希码,并确保您的相等比较函数 (override bool object.Equals(object)) 工作正常。 HashSet 将在哈希匹配时进行相等性检查,以处理哈希冲突。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-20
      • 1970-01-01
      • 2020-04-10
      • 1970-01-01
      • 1970-01-01
      • 2021-02-07
      • 1970-01-01
      相关资源
      最近更新 更多