【问题标题】:Intersection of two sets in most optimized way以最优化的方式交叉两个集合
【发布时间】:2013-01-09 18:12:22
【问题描述】:

给定两组值,我必须找出它们之间是否有任何共同元素,即它们的交集是否为空。

哪个标准 C# 集合最适合此目的(就性能而言)?我知道linq 有一个Intersect 扩展方法来找出两个列表/数组的交集,但我的重点是Big-O notation 方面的性能。

如果我还必须找出两组的交集呢?

【问题讨论】:

  • “Big O”不是性能指标,而是复杂性指标。

标签: c# performance set


【解决方案1】:

如前所述,应用Any() 会给你一些性能。

我在相当大的数据集上对其进行了测试,结果提高了 25%。

另外应用larger.Intersect(smaller) 而不是相反是非常重要的,就我而言,它带来了 35% 的改进。

在应用 intersect 之前对列表进行排序还可以获得 7-8%。

要记住的另一件事是,根据用例,您可以完全避免应用相交。

例如,对于整数列表,如果最大值和最小值不在同一个边界内,则不需要应用 intersect,因为它们永远不会。

同样适用于第一个字母的字符串列表。

再次根据你的情况,尽可能多地尝试找到一个规则,其中交集是不可能避免调用它的。

【讨论】:

  • 非常感谢您进行性能测试。为我节省了很多时间试图弄清楚如何优化我的代码。
【解决方案2】:

好吧,如果您使用 LINQ 的 Intersect 方法,它将构建第二个序列的 HashSet,然后对照它检查第一个序列的每个元素。所以它是 O(M+N)... 你可以使用foo.Intersect(bar).Any() 提前退出。

当然,如果您将一个(任一)集合存储在 HashSet<T> 中开始,您可以迭代另一个集合,检查每个步骤的包含情况。不过,您仍然需要先构建集合。

从根本上说,无论你做什么,你都会遇到 O(M+N) 的问题 - 你不会得到比这更便宜的(总是你必须看看的可能性每个元素),如果您的哈希码是合理的,您应该能够轻松实现这种复杂性。当然,某些解决方案可能会比其他解决方案提供更好的常数因子……但这是性能而不是复杂性;)

编辑:如 cmets 中所述,还有 ISet<T>.Overlaps - 如果您已经设置了静态类型 ISet<T> 或具体实现,调用 Overlaps 可以更清楚地了解您在做什么.如果两个你的集合都静态类型为ISet<T>,请使用larger.Overlaps(smaller)(根据集合的大小,更大和更小),因为我希望实现Overlaps遍历 argument 并根据您调用它的集合的内容检查每个元素。

【讨论】:

  • 如果foobar 都实现ISet,我认为foo.Overlaps(bar) 应该是最好的选择,并且工作速度更快或等于foo.Intersect(bar).Any()
  • @YMC:老实说,我希望它们几乎是平等的。 Overlaps 可能会稍微快一点,因为它可以避免在内部创建额外的集合。当然,这也更明显 - 我会将其添加到答案中。
  • 如果我们必须在超过 2 个哈希集之间取一个交集怎么办?例如我们必须取 6 个哈希集的交集,即 hs1、hs2、hs3、hs4、hs5、hs6?而且我们事先不知道我们有 6 个或任意数量的哈希集?
  • @FarazAhmad:我建议不要在 cmets 中探索这个问题,而是提出一个新问题,例如你想要什么等 :)
  • @StephenHolt:我对此表示怀疑。在我看来,这听起来可能会慢得多。
猜你喜欢
  • 1970-01-01
  • 2021-05-21
  • 2015-06-23
  • 1970-01-01
  • 1970-01-01
  • 2021-06-16
  • 2018-01-21
  • 2018-12-17
  • 2018-10-04
相关资源
最近更新 更多