以最优化的方式交叉两组

时间:2013-01-25 17:55:46

标签: c# set

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

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

如果我必须找出两组的交集怎么办?

2 个答案:

答案 0 :(得分:36)

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

当然,如果您将{(1}}中的一个(任一个)设置为开始,您可以迭代检查另一个检查每个步骤的包含。尽管如此,你仍然需要构建集合。

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

编辑:如评论中所述,还有ISet<T>.Overlaps - 如果您已经设置了静态类型HashSet<T>或具体实现,则调用ISet<T>使其成为可能更清楚你在做什么。如果两个的集合被静态输入为Overlaps,请使用ISet<T>(根据集合的大小越来越大),因为我期望实现larger.Overlaps(smaller)迭代参数,并根据您调用它的集合的内容检查每个元素。

答案 1 :(得分:7)

如上所述,应用Any()会给你一些表现。

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

同样适用larger.Intersect(smaller)而不是相反,非常重要,在我的情况下,它提供了35%的改进。

在应用交叉之前对列表进行排序还有7-8%。

另外要记住的是,根据用例,您可以完全避免应用交叉。

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

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

再次根据您的情况,尽可能多地尝试找到一个规则,其中交叉点无法避免调用它。