内置.NET集合分拣机的性能

时间:2010-09-17 20:30:53

标签: .net performance sorting collections

有人询问如何对List进行排序。从基本的List.Sort()到List.OrderBy()给出了几种方法。最可笑的是一个自己动手的Se​​lectionSort。我立刻投了票,但它让我思考; Linq的OrderBy(),应用于列表,不会做同样的事情吗? myList.OrderBy(x => x.Property).ToList()将产生一个迭代器,它基本上在集合的左边找到投影的最小值,并且yield返回它。在浏览整个列表时,这是一种选择排序。

这让我想到了; Lists,SortedLists,Enumerables等内置分类器使用什么算法,并且通过扩展,它们是否应该避免大型集合中的任何一个? SortedList,因为它按键排序,可能会在每次添加时使用单次传递InsertionSort;找到第一个索引,其值大于新索引,并在其之前插入。列表和数组可能MergeSort本身非常有效,但我不知道Sort()背后的实际算法。我们已经讨论过OrderBy。

我上面所知道的似乎表明List.Sort()或Array.Sort()是已知大小列表的最佳选项,并且不鼓励使用Linq对内存列表或数组进行排序。对于一个流,那么OrderBy()确实没有任何其他方法可枚举;由于您可以将数据保存为流而不必在排序之前完成所有操作,因此可以减轻性能损失。

编辑:

普遍的共识是,给定List或Array的具体实现,Sort()更快。 OrderBy是合理的但速度较慢,因为它增加了从传递的可枚举中提取数组的O(N)复杂性。 SortedList初始化最终为O(N ^ 2),因为它的内幕是什么。故事的道德,当你有一个实际的List时,使用List.Sort()而不是List.OrderBy()。

4 个答案:

答案 0 :(得分:7)

Enumerable.OrderBy()啜饮IEnumerable&lt;&gt;进入数组并使用快速排序。 O(n)存储要求。它由System.Core.dll中的内部类EnumerableSort<TElement>.QuickSort()完成。如果您有一个列表,那么存储成本使得它只是简单地对列表进行排序就没有竞争力,因为List&lt;&gt;就地排序。 Linq经常通过使用is运算符检查IEnumerable的真实功能来优化。因为List&lt;&gt; .Sort是破坏性的,所以不会在这里工作。

List&lt;&gt; .Sort和Array.Sort使用就地快速排序。

排序列表&LT;&GT;具有O(n)插入的复杂性,主导O(log(n))查找插入点的复杂性。因此,将N个未分类的项目放入其中将花费O(n ^ 2)。 SortedDictionary&LT;&GT;使用红黑树,给出插入O(log(n))的复杂性。因此O(nlog(n))填充它,与摊销快速排序相同。

答案 1 :(得分:4)

快速通过反射器告诉我,List Sort方法通过System.Collections.Generic.GenericArraySortHelper使用快速排序http://en.wikipedia.org/wiki/Quicksort

SortedList使用Array.BinarySearch来确定在每个Add

上插入内容的位置

枚举器没有排序逻辑

Quicksort对于大多数情况来说是一个很好的排序选择,但如果你真的不太喜欢输入数据它可以接近O(n ^ 2)。

如果您怀疑您的输入数据是快速排序的不幸(已经排序)顺序中的巨大数据堆,则首先将数据随机化(这总是很便宜)然后执行对随机数据进行排序。快速排序算法可以实现一些技巧来缓解排序已经排序(或接近排序)的输入数据的问题,我不知道BCL实现是否做了这些。

答案 2 :(得分:4)

找出每种方法的性能的一种方法是测量它:

List<int> createUnsortedList()
{
    List<int> list = new List<int>();
    for (int i = 0; i < 1000000; ++i)
        list.Add(random.Next());
    return list;
}

void Method1()
{
    List<int> list = createUnsortedList();
    list.Sort();
}

void Method2()
{
    List<int> list = createUnsortedList();
    list.OrderBy(x => x).ToList();
}

结果:

  • 方法1:0.67秒(List.Sort)
  • 方法2:3.10秒(OrderBy)

这表明即使对于非常大的列表,OrderBy的性能也是合理的,但它并不像在列表中使用内置的Sort方法那么快。这可能是因为OrderBy的代码稍微灵活一些 - 它需要一个必须为每个元素计算的键选择器。

答案 3 :(得分:4)

是的,你的假设听起来不错。我做了一点测试来证实它。

在5000000个整数上,

data.Sort();                           //  500 ms
data = data.OrderBy(a => a).ToList();  // 5000 ms