为什么我大多数时候听说快速排序是最快的整体排序算法,但根据维基百科,Timsort似乎表现更好?
为什么我大多数时候听说快速排序是最快的整体排序算法,但根据维基百科,Timsort似乎表现更好?
TimSort是一种高度优化的归并排序,它是稳定的,并且比旧的归并排序更快。
与快速排序相比,它有两个优点:
老实说,我不认为#1是一个优点,但它确实给我留下了深刻的印象。
以下是快速排序的优点:
目前,Java 7 SDK实现了timsort和新的快速排序变体:即双轴快速排序。
如果你需要稳定排序,请尝试timsort,否则请从快速排序开始。
一般来说,快速排序是适用于原始数组的最佳算法。这是因为它具有内存局部性和高速缓存。
JDK7使用TimSort来处理对象数组。对象数组只保存对象引用,而对象本身存储在堆中。要比较对象,我们需要从堆中读取对象。这就好像从堆的一个部分读取一个对象,然后从另一个部分随机读取对象。这将导致大量的高速缓存未命中。我猜这就是为什么内存局部性不再重要的原因。也许这就是JDK为什么只对对象数组使用TimSort而不对原始数组使用的原因。
这只是我的猜测。
如果您需要进行保序排序或对复杂数组(比较基于堆的对象)进行排序,那么Tim Sort非常适合;而快速排序则对基本数组的数据局部性和处理器缓存有很大的好处。
快速排序的最坏情况是O(n^2),这个问题也被提出过。幸运的是,您可以通过在快速排序中实现O(n log n)最坏时间复杂度来解决这个问题。快速排序的最坏情况发生在枢轴点是最小值或最大值时,例如当枢轴是已排序数组的第一个或最后一个元素时。
我们可以通过将枢轴设置为中位数来实现O(n log n)最坏情况下的快速排序。由于在线性时间O(n)内找到中位数,因此O(n) + O(n log n) = O(n log n),这成为最坏情况的时间复杂度。
但是在实践中,大多数实现都认为随机选取枢轴就足够了,因此不会搜索中位数。
$ ./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
所以你真的无法确定。基准测试数据只保持相关性最多两年,然后你必须重复进行测试。可能在问题被问出时,timsort 在 2011 年远胜于 qsort,但是时代已经改变。或者 qsort 总是最快的,但 timsort 在非随机数据上胜过它。或者 Swenson 的代码并不那么好,更好的程序员会使 timsort 更有优势。或者也许是我糟糕透顶,没有在编译代码时使用正确的 CFLAGS
。或者...你明白我的意思。
heapq.merge
)并不是很高效(其中大部分是用Python而不是C实现的)。因此,合并已经排序的数据或将未排序的数据添加到排序的数据的常见方法是只需执行:sortedlist += newdata; sortedlist.sort()
(或一行代码,sortedlist = sorted(sortedlist + newdata)
)。如果TimSort不使用现有的排序,则这将非常低效。 - ShadowRangerTimsort是一种流行的混合排序算法,由Tim Peters于2002年设计。它结合了插入排序和归并排序。它被开发出来以在各种真实世界的数据集上表现良好。它是一种快速、稳定和自适应的排序技术,平均和最坏情况下的性能为O(n log n)
。
Timsort的工作原理
Timsort的优点
Quicksort是一种高效的排序算法,它将大型数据数组分成较小的数组,并基于分治的概念。Tony Hoare于1959年设计了这种排序算法,平均性能为O(n log n)
。
Quicksort的工作原理
快速排序的优点