我想知道this post中实施的快速排序的复杂性。
斯图尔特马克斯说这是O(N ^ 2 log N)。但它真的吗?我不明白这些话:在我看来 - 再一次,我不是C#或.NET专家 - 这将导致某些看似无害的调用,例如通过ints.First()进行数据透视选择,更加昂贵比他们看起来。当然,在第一级,它是O(1)。但是考虑在树的深处,在右边缘。要计算此分区的第一个元素,必须遍历整个源,即O(N)操作。但由于上面的分区是惰性的,因此必须重新计算它们,需要进行O(lg N)比较。因此,选择枢轴将是O(N lg N)操作,这与整个操作一样昂贵。
为什么ints.First()
会成为O(N)操作?我认为它总是O(1)。为什么必须重新计算IEnumerables
树中的上面的分区?这对我来说也没有任何意义。 IEnumerable.Where
不会返回新的IEnumerable吗?在我看来,这个算法的时间复杂度仍然是O(N log N),但空间复杂度也是O(N log N),而不仅仅是我们在原地排序的O(N)。
总而言之,Stuart Marks是对还是我是对的?
答案 0 :(得分:3)
IEnumerable<>
没有缓存。如果它由一个集合支持(比如新的int[5].AsEnumerable()
),那么你可以重复使用它多少次,但理论上可以IEnumerable<>
生成一个邮件,一次一个元素,并且在内存中你将只拥有当前元素,并且忘记了之前的元素。无法保证枚举两次IEnumerable<>
将返回相同的数据,也无法保证枚举两次。你联系的问题非常愚蠢,并表明海报并不知道他在说什么。
提议的QuickSort(IEnumerable<int> ints)
有一个参数IEnumerable<int> ints
。该方法没有任何外部保证IEnumerable<int> ints
可以枚举两次,或者访问它甚至一次不会导致O(N)操作。
现在...... .First()
可能是O(N)操作,或者更糟糕的是,例如,如果必须订购支持集合......如果您QuickSort(new[] { 5, 4, 3, 2, 1}.OrderBy(x => x))
,那么{{1}执行时需要等待执行pars.First()
,OrderBy()
必须先查看整个后备OrderBy()
(IEnumerable<>
)才能对其进行排序(所以至少O(N))
A&#34;有趣&#34; new[] { }
上的First()
的示例,IEnumerable<>
上的O(N)将在每次执行时给出不同的结果。
private static int seed = 0;
public static IEnumerable<int> GetSomeInts()
{
var rnd = new Random(seed++);
for (int i = 0; i < 10; i++)
{
Console.Write(".");
yield return rnd.Next(100000);
}
}
for (int i = 0; i < 10; i++)
{
Console.WriteLine(GetSomeInts().OrderBy(x => x).First());
}
您可以从&#34;。&#34;的数量中看到O(N)
。打印。尝试删除OrderBy()
并观察结果。关于IEnumerable<>
每次执行都会返回不同结果的事实......嗯......有一个for
周期:-)尝试查看结果。