使用IEnumerable实现的快速排序的复杂性是多少?

时间:2018-05-29 07:28:18

标签: c# algorithm linq

我想知道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是对还是我是对的?

1 个答案:

答案 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周期:-)尝试查看结果。