时间:2011-10-14 15:51:32

标签: algorithm sorting quicksort timsort

为什么当timsort(根据维基百科)表现得更好时,我大多听说quicksort是最快的整体排序算法?谷歌似乎没有发现任何比较。

5 个答案:

答案 0 :(得分:35)

TimSort是高度优化的mergesort,它比旧的mergesort更稳定,更快。

与quicksort比较时,它有两个优点:

  1. 几乎排序的数据序列(包括反向排序数据)的速度令人难以置信;
  2. 最坏的情况仍然是O(N * LOG(N))。
  3. 说实话,我不认为#1是一个优势,但它给我留下了深刻的印象。

    以下是QuickSort的优势

    1. QuickSort非常简单,即使是高度优化的实现,我们也可以在20行内写下它的pseduo代码;
    2. QuickSort在大多数情况下是最快的;
    3. 内存消耗为LOG(N)。
    4. 目前,Java 7 SDK实现了timsort和一个新的快速排序变体:即Dual Pivot QuickSort。

      如果你需要稳定排序,请尝试timsort,否则从quicksort开始。

答案 1 :(得分:25)

或多或少,它与Timsort是混合排序算法的事实有关。这意味着虽然它使用的两个基础排序(Mergesort和插入排序)对于多种数据都比Quicksort更差,但Timsort仅在有利的情况下使用它们。

在更深层次上,如Patrick87个状态,quicksort是最坏情况的O(n 2 )算法。选择一个好的支点不是hard,但保证O(n log n)快速排序的代价是平均排序通常较慢。

有关Timsort的更多详细信息,请参阅this answer和链接的博文。它基本上假定大多数数据已经部分排序,并构造排序数据的“运行”,允许使用mergesort进行有效的合并。

答案 2 :(得分:15)

一般来说,quicksort是原始数组的最佳算法。这是由于内存位置和缓存。

JDK7使用TimSort for Object数组。对象数组仅包含对象引用。对象本身存储在Heap中。要比较对象,我们需要从堆中读取对象。这就像从一个对象的堆的一部分读取,然后从堆的另一部分随机读取对象。将会有很多缓存未命中。我想因为这个原因记忆局部性不再重要了。这可能是JDK仅使用TimSort for Object数组而不是原始数组的原因。

这只是我的猜测。

答案 3 :(得分:5)

以下是我的机器的基准数字(i7-6700 CPU,3.4GHz,Ubuntu 16.04,gcc 5.4.0,参数:SIZE = 100000和RUNS = 3):

$ ./demo 
Running tests
stdlib qsort time:                 12246.33 us per iteration
##quick sort time:                  5822.00 us per iteration
merge sort time:                    8244.33 us per iteration
...    
##tim sort time:                    7695.33 us per iteration
in-place merge sort time:           6788.00 us per iteration    
sqrt sort time:                     7289.33 us per iteration    
...
grail sort dyn buffer sort time:    7856.67 us per iteration

基准测试来自Swenson的sort项目,他在C#中实现了几种排序算法。大概是,他的实现很好,具有代表性,但我没有& #39; t调查他们。

所以你真的无法说出来。基准数字只保留最多两年,然后你必须重复它们。可能是,当问到这个问题时,timsort在2011年击败了qsort waaay,但时代已经改变。或者qsort总是最快的,但是timsort在非随机数据上击败了它。或者Swenson的代码并不是那么好,一个更优秀的程序员可以帮助扭转时尚潮流。或许我在编译代码时很糟糕并且没有使用正确的CFLAGS。或者......你明白了。

答案 4 :(得分:1)

如果需要保持顺序排序,或者要对复杂数组(比较基于堆的对象)而不是原始数组进行排序,则Tim Sort非常有用。正如其他人所提到的,快速排序显着受益于数据的位置和原始数组的处理器缓存。

提出了快速排序的最坏情况是O(n ^ 2)的事实。幸运的是,您可以使用quicksort实现O(n log n)时间最坏的情况。当枢轴点是最小值或最大值时,例如当枢轴是已排序数组的第一个或最后一个元素时,就会发生快速排序的最坏情况。

通过将枢轴设置为中值,可以实现O(n log n)最坏情况的快速排序。由于找到中值可以在线性时间O(n)中完成。因为O(n)+ O(n log n)= O(n log n),所以这成为最坏情况下的时间复杂度。

但是,实际上,大多数实现发现随机支点就足够了,因此不必搜索中间值。