.NET List <t> .Sort使用introsort,为什么最坏的情况是O(n ^ 2)?

时间:2018-11-17 15:10:56

标签: c# .net algorithm sorting

List<T>.Sort的.NET文档提到了渐近运行时:https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.sort?view=netframework-4.7.2

  

平均而言,此方法是O(n log n)运算,其中n是Count;在最坏的情况下,它是O(n ^ 2)运算。

它还提到它是使用Array.Sort实现的,它在https://docs.microsoft.com/en-us/dotnet/api/system.array.sort?view=netframework-4.7.2处也有运行时声明

  

对于使用Heapsort和Quicksort算法排序的数组,在最坏的情况下,此方法是O(n log n)运算,其中n是长度。

它还提到了introsort在2012年开始与.NET 4.5一起使用。

在最坏的情况下,为什么List<T>.Sort仍然是O(n ^ 2)?还是这只是文档中的一个错误,实际上是O(n log n)?

2 个答案:

答案 0 :(得分:2)

我认为这可能是一个近似问题。拿第二个报价:

  

对于使用Heapsort和Quicksort算法排序的数组,在最坏的情况下,此方法是O(n log n)运算,其中n是长度。

我已经看到大量教科书/文章将quicksort定义为O(n log n),而实际上您可以仔细检查here并验证其最坏情况的成本实际上是O(n²)。这通常是因为在实践中,快速排序几乎总是比其他在纸张上具有最坏情况成本较小的排序算法快。例如,您会看到块排序的最坏情况是O(n log n),但是在大多数实际应用中,快速排序仍然会更快。

至于您的第一句话:我想说这是因为文档提到了可能情况下最糟糕的事情。具体来说:

  • 如果分区的大小小于16,则会进行插入排序,即O(n²)(尽管由于其边界为16,因此在这里可以视为O(1))。
  • 如果分区[…]随堆排序一起使用,则为O(n log n)。
  • 否则,它与quicksort一起使用,实际上是O(n²)。

所以我想说这可能就是为什么List<T>.Sort方法被平均描述为O(n log n),而在最坏的情况下被描述为O(n²)的原因。

答案 1 :(得分:2)

Introsort在最坏的情况下为O(n log n)。

据我所知,内省排序首先存在的唯一原因是为了避免快速排序的O(n 2 )最坏情况下的运行时间。

所以说它是O(n 2 )的链接是错误的。

请注意,这两个链接给出了完全相同的算法,即逐字(减去看起来是打字错误的地方-Log N 而不是log N)。

  
      
  • 如果分区大小少于16个元素,则使用插入排序算法

  •   
  • 如果分区数超过2 log n,其中n是输入数组的范围,它将使用Heapsort算法。

  •   
  • 否则,它使用Quicksort算法。

  •   

但是,它们的结论是得出不同的最坏情况复杂性。

  

in the worst case, this method is an O(n log n) operation

  

in the worst case it is an O(n2) operation