为什么当timsort(根据维基百科)表现得更好时,我大多听说quicksort是最快的整体排序算法?谷歌似乎没有发现任何比较。
答案 0 :(得分:35)
TimSort是高度优化的mergesort,它比旧的mergesort更稳定,更快。
与quicksort比较时,它有两个优点:
说实话,我不认为#1是一个优势,但它给我留下了深刻的印象。
以下是QuickSort的优势
目前,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),所以这成为最坏情况下的时间复杂度。
但是,实际上,大多数实现发现随机支点就足够了,因此不必搜索中间值。