【问题标题】:How are .NET compilers able to construct O(1) lookups for any T in a HashSet<T>?.NET 编译器如何为 HashSet<T> 中的任何 T 构造 O(1) 查找?
【发布时间】:2015-11-20 17:23:02
【问题描述】:

我不明白编译器如何足够聪明地为 MyObject 构建 O(1) 查找,我可以将 anything 放入其中

public class MyObject
{
    // ... 
}

我了解如何为有限数量的非原始对象完成此操作,例如

public class MyObject
{
    int i { get; set; }
    char c { get; set; }
}

但它怎么可能知道如何为MyObject 的任何实现执行此操作?

【问题讨论】:

  • 它是通过将一个对象变成一个数字来完成的。然后将其用作集合中的索引。谷歌“哈希函数”并阅读您最喜欢的有关 Object.GetHashCode() 的 C# 语言书籍。
  • 我认为这不足以将其标记为重复,但我深入解释了 Dictionary(和 HashSet)如何使用哈希码进行 O(1) 查找in this answer
  • Protip:如果你创建一个struct,这一切都是免费的:D
  • 不,你不明白如何为有限数量的非原始人做到这一点。您将使用 MyObject 进行 0(1) 查找。问题是具有相同 i can c 的两个 MyObject 将不相等。它们将是 HashSet 中的两个条目。

标签: c# .net data-structures


【解决方案1】:
  1. 获取哈希码
  2. 将其取模以生成数组索引。
  3. 看那里。如果某个项目存在,请查看它是否相等。

到目前为止,完美的 O(1)。如果许多项目最终具有以相同索引为模的哈希码,它就会下降。这种情况发生了一点是意料之中的,并得到了处理,但如果它一直发生,你最终会出现 O(n) 的行为(并且具有非常糟糕的恒定成本)。

默认情况下,所有对象都有一个基于引用标识的GetHashCode() 和一个Equals()(也就是说,它们只等于它们自己)。覆盖这些更改是它具有的相等概念,因此当您更改 Equals() 时必须始终更改 GetHashCode()(所有相等的对象必须具有相同的哈希码)。您还可以通过使用IEqualityComparer&lt;T&gt; 实现来强制使用不同的相等概念,该实现提供不同的GetHashCode()Equals() 供使用。

【讨论】:

    【解决方案2】:

    每个对象都有一个与之关联的Hash Code。有一个方法GetHashCode (在基类object 中定义为virtual) 必须在类中重写,这样HashSet 才能正常工作。

    哈希码是一个数值,用于插入和识别 基于散列的集合中的对象,例如 字典类、Hashtable 类或派生类型 来自 DictionaryBase 类。 GetHashCode 方法提供了这个 需要快速检查对象相等性的算法的哈希码。

    对于您当前的课程,它无法正常工作(因为GetHashCode 未被覆盖)。相等性的比较将根据参考而不是实际值进行。

    【讨论】:

    • 它将与他们的班级一起工作,只是使用默认的基于身份的平等。
    • 啊,好的。 “必须被覆盖”是我不知道的。我假设从 object 继承的所有东西都已经有一个公式,有一些通用的公式足以适用于任何扩展 object
    • @JonHanna,是的,它将基于引用相等,而不是实际值。
    猜你喜欢
    • 2021-02-08
    • 2014-01-02
    • 2011-12-13
    • 1970-01-01
    • 1970-01-01
    • 2010-12-08
    • 1970-01-01
    • 2015-09-12
    • 1970-01-01
    相关资源
    最近更新 更多