【问题标题】:Is HashSet<T> the fastest container to look up in?HashSet<T> 是查找速度最快的容器吗?
【发布时间】:2011-01-16 13:41:43
【问题描述】:

我需要检查特定字符串是否包含在其他字符串中:

private bool Contains(string field)
{
   return this.Fields.Contains(field); // HashSet<string> local property
}

如果只有一项任务,最好使用哪种容器类型 - 保存多个字符串并检查另一个字符串是否进入?

【问题讨论】:

    标签: c# .net contains hashset


    【解决方案1】:

    HashSet 有效吗?当然。但这不是你问的问题。您要求尽可能快的查找。

    这是最快的吗?不,当然不是,无论如何都不是。

    首先,为了谈论“最快”,我们需要准确描述“最快”的含义。你的意思是:

    • 最小的最坏情况时间
    • 最小的平均多次计时的平均时间
    • 最小平均时间给定特定的使用模式
    • 别的东西

    ?请准确说明“尽可能快”的含义。只有当我们确切地知道最快对您意味着什么时,我们才能为您设计一个理论上最快的算法。

    例如,假设您正在编写一个编译器。在编译器中我们必须一直做的事情是检查特定字符串是否在字符串列表中。也许我们正在检查字符串是否是关键字,因此我们必须查找给定字符串是否在集合内 {"int", "double", "for", "foreach", "class" ... }

    我们可以将它们放入哈希集中并获得不错的性能。但如果我们想要可能的最佳性能,我们可以做得更好。例如,我们可以对数十亿行现有源代码进行分析,找出哪些关键字最常见,哪些最不常见,然后编写一个自定义哈希表,针对 (1) 快速拒绝根本不是关键字,并且 (2) 以识别其他关键字为代价快速识别最常见的关键字。

    注意,这需要静态分析;尽管它在典型情况下表现良好,但在使用大量稀有关键字的罕见情况下表现不佳。我们可以采取的另一种方法是编写一个自我调整哈希表,该哈希表动态识别特定字符串何时被频繁搜索。

    考虑一下,例如,如果您正在编写 JScript 运行时的实现。我们经常必须在一组字符串中寻找一个字符串:

    for(i = 0; i < 10; ++i) { foo.bar(i); }
    

    这里我们必须在“foo”标识的对象中查找字符串“bar”十次。 “foo”中实现该查找的哈希表在循环中第一次注意到“bar”已被使用,因此它动态调整哈希表结构,以便 second 时间通过循环,查找速度更快。这是我们在实现 JScript 时采用的策略。

    现在,这优化了 for 循环的情况,但它使这种情况可能比它可能的慢:

    for(i = 0; i < 10; ++i) { foo.bar(i); foo.blah(i); foo.abc(i); }
    

    因为我们没有做更多的分析并意识到“嘿,我们只是重新优化了这个哈希表 3 次,现在我们要重新做一遍,也许我们应该保持原样。”

    幸运的是,我们没有像您一样寻找最快的查找。我们只是在寻找相当快的查找。

    您能否仔细而完整地描述最快查找的具体使用案例?您可以使用许多算法来加快查找速度,但它们变得非常复杂。

    【讨论】:

    • 埃里克,非常感谢您提供如此高级的答案!我认为我的用例非常简单。我的 asp.net 应用程序中的页面有一些 asp.net 2.0 控件(例如 DetailsView 或 GridView)。此页面的超类创建一个字典,其中控件的数据字段是键,适当的本地化字符串是值。超类调用 HashSet 的覆盖属性包含特定页面所需的字段集,并动态创建单选按钮列表。这是一个搜索面板。因此,在迭代字典时,我必须询问页面是否包含选定字段以将其插入表中。
    • @abatishchev:您是否有任何证据表明您的应用程序的性能受到此查找的限制?也就是说,这种查找是您的应用程序中最慢的事情吗?如果这不是门控因素,那么您为什么要关心它是否尽可能快?找出最慢的组件并提高性能。
    • 是的,我当然同意你的开发策略建议!只是我需要说,我的发展首先是教育,所以这只是我如何尝试更多地了解......例如通用容器的一个例子。
    • 关于平均与最坏情况性能的一个有趣点是,当您将恶意数据放入哈希表时,攻击者通常会引发最坏情况性能,例如导致 n 次插入需要 O(n^2)时间而不是通常的 O(n)。因此,Web 应用程序中存在许多 DoS 服务漏洞。
    【解决方案2】:

    是的,HashSet 非常适合这一点,因为它包含一个要查找的值,不像字典需要一个键和一个值。

    【讨论】:

      猜你喜欢
      • 2010-11-06
      • 2012-04-06
      • 1970-01-01
      • 1970-01-01
      • 2014-09-15
      • 2017-04-10
      • 2013-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多