在创建3个IEnumerables的并集时,实现O(n)性能的最简单方法是什么?
说a,b,c都是List
,我想创建一个未排序的联合。 虽然性能不是超级关键,但它们每个可能有10,000个条目,所以我很想避免使用O(n ^ 2)解决方案。
AFAICT MSDN文档没有说明关于union的性能特征,就不同类型而言。
我的直觉说,如果我只是做一个。 a.Union(b).Union(c)
,这将需要O(n ^ 2)时间,但是new Hashset(a).Union(b).Union(c)
将是O(n)。
有没有人有任何文件或指标来确认或否认这一假设?
您应该使用Enumerable.Union
因为它与HashSet
方法一样高效。 复杂度为O(n + m),因为:
Enumerable.Union
当枚举此方法返回的对象时,
Union
e 按该顺序计算第一个和第二个,并产生尚未产生的每个元素。
源代码在这里 。
Ivan是对的,如果你使用带有多个集合的Enumerable.Union
会有一个开销,因为必须为每个链式调用创建一个新集合。 因此,如果您使用以下方法之一,它可能会更有效(就内存消耗而言):
-
Concat
+Distinct
:a.Concat(b).Concat(c)...Concat(x).Distinct()
-
Union
+Concat
a.Union(b.Concat(c)...Concat(x))
-
采用
IEnumerable
HashSet
构造函数 (fe withint
):new HashSet
(a.Concat(b).Concat(c)...Concat(x))
前两者之间的差异可以忽略不计。 第三种方法不使用延迟执行,它在内存中创建HashSet<>
。 这是一种优秀而有效的方法1.如果您需要此集合类型或2.如果这是查询的最终操作。 但是如果你需要对这个链式查询进行进一步的操作,你应该更喜欢Concat + Distinct
或Union + Concat
。
虽然@Tim Schmelter关于Enumerable.Union
方法的线性时间复杂度是正确的,但链接多个Union
运算符具有隐藏的开销,每个Union
运算符在内部创建一个哈希集,该哈希集基本上复制了前一个运算符(加上其他项)的哈希集,因此与单个HashSet
方法相比,使用更多内存。
如果我们考虑到Union
只是Concat
+ Distinct
的快捷方式,那么具有与HashSet
相同的时间/空间复杂度的可伸缩LINQ解决方案将是:
a.Concat(b).Concat(c)...Concat(x).Distinct()
Union
是O(n)。
a.Union(b).Union(c)
在大多数实现中的效率低于a.Union(b.Concat(c))
因为它为第一个union操作创建一个哈希集,然后为另一个a.Union(b.Concat(c))
创建另一个哈希集,如同其他答案说。 这两者最终都会使用一系列IEnumerator
对象,这会增加成本,因为会增加更多的资源。
a.Union(b).Union(c)
在.NET Core中效率更高,因为第二个.Union()
操作产生一个知道a
, b
和c
的单个对象,它将为整个创建一个哈希集操作,以及避免IEnumerator
对象链。