代码之家  ›  专栏  ›  技术社区  ›  Coder-Man

使用IEnumerable实现QuickSort的复杂性是什么?

  •  0
  • Coder-Man  · 技术社区  · 8 年前

    我想知道在 this post .

    斯图亚特·马克斯说是O(n^2 logn)。但这真的吗?我不明白这些话:

    在我看来——再一次,我不是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 logn),但是空间复杂度也是O(n logn),而不仅仅是O(n),我们在哪里排序。

    总之,斯图亚特·马克斯是对的还是我是对的?

    1 回复  |  直到 8 年前
        1
  •  3
  •   xanatos    8 年前

    这个 IEnumerable<> 不缓存。如果它由集合支持(如新的 int[5].AsEnumerable() )然后你可以重复使用它多少次,但是 理论上,可以一次生成一个零碎的元素,在内存中,只有当前的元素,而之前的元素被遗忘了。不能保证枚举两次 IEnumerable<gt; 将返回相同的数据,也不可能枚举两次。你链接的问题很愚蠢,表明海报不知道他在说什么。

    这个 QuickSort(IEnumerable<int> ints) 建议有一个参数 IEnumerable<int> ints . 该方法没有任何外部保证 IEnumerable<int>整数 可以枚举两次,或者即使访问一次也不会导致O(N)操作。

    现在。。。 .First() 可能是O(N)操作,或者更糟,例如,如果必须订购支持集合…如果你 QuickSort(new[] { 5, 4, 3, 2, 1}.OrderBy(x => x)) 然后 pars.First() 执行后需要等待 OrderBy() 待执行,以及 排序依据() 必须先看看整个背衬 IEnumerable<gt; (the new[] { } )对其进行排序(因此至少为o(n))

    “有趣”的例子 First() 那是O(N)o n a IEnumerable<gt; 每次执行时都会给出不同的结果。

    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());
    }
    

    你可以看到 O(N) 从打印的“.”号开始。尝试删除 排序依据() 观察结果。关于这个事实 IEnumerable<gt; 每次执行时都会返回不同的结果…好。。。有一个 for 循环:-)尝试查看结果。