哪种排序算法在大部分已排序数据上表现最好?
基于观看动画gif的高度科学方法,我认为插入排序和冒泡排序是不错的选择。
仅有少量项目 => 插入排序
项目大多已排序 => 插入排序
担心最坏情况 => 堆排序
对良好的平均情况结果感兴趣 => 快速排序
项目来自密集的范围内 => 桶排序
希望尽可能少的编写代码 => 插入排序
Timsort 是一种“自适应、稳定、自然合并排序”,在许多部分有序的数组中表现出“超自然的性能(需要少于 lg(N!) 的比较,最少 N-1 次)”。Python内置的sort()
算法已经使用此算法相当长一段时间,并取得了良好的效果。它专门设计用于检测和利用输入中部分排序的子序列,这通常在真实数据集中经常发生。在现实世界中,往往比交换列表中的项目要昂贵得多的是比较操作,因为通常只需交换指针,这往往使timsort成为一个很好的选择。但是,如果您知道您的比较操作总是非常便宜的(例如编写一个程序来对32位整数进行排序),则可能存在其他算法,其性能可能更好。当然,利用timsort最简单的方法是使用Python,但由于Python是开源的,您也可以借用其代码。或者,上述描述包含足够的细节,可以编写您自己的实现。
O(n)
为止!@behrooz: 任何比较排序的平均情况都无法优于O(n log n)
,而lg(n!)
是O(n log n)
。因此,timsort的最坏情况渐近复杂度不会比任何其他比较排序更差。此外,它的最佳情况比任何其他比较排序都要好或相等。 - Artelius使用如下行为的插入排序:
1..n
中的每个元素 k
,首先检查 el[k] >= el[k-1]
是否成立。如果成立,则继续下一个元素。(显然跳过第一个元素)1..k-1
中使用二分查找来确定插入位置,然后将元素向右移动。(如果 k>T
,其中 T
是某个阈值,则可能只需要这样做;对于小的 k
这是过度工作)。该方法进行的比较次数最少。
尝试使用内省排序(Introspective Sort) http://en.wikipedia.org/wiki/Introsort
该算法基于快速排序(Quicksort),但它避免了快速排序在几乎有序列表上出现最坏情况的行为。
这个排序算法的技巧是检测快速排序进入最坏情况模式的情况,并切换到堆排序或归并排序。一些非朴素的分区方法用于检测几乎有序的分区,并使用插入排序处理小分区。
你可以通过付出更多代码和复杂性的代价,获得所有主要排序算法的优点。无论数据如何,您都可以确保不会遇到最坏情况。
如果你是C++程序员,请检查std::sort算法。它可能在内部已经使用内省排序。
Splaysort 是一种基于splay trees(一种自适应二叉树)的鲜为人知的排序方法。Splaysort 不仅适用于部分排序数据,还适用于部分反向排序数据或者任何已有某种预定顺序的数据。它在一般情况下是O(nlogn),在数据以某种方式排序(正向、反向、管风琴等)的情况下是O(n)。
与插入排序相比,它最大的优点是当数据没有排序时不会退化为O(n^2)行为,因此您不需要绝对确定数据是部分排序的才能使用它。
它的缺点是需要额外的空间开销来存储所需的splay tree结构,以及构建和销毁splay tree所需的时间。但是,根据您期望的数据大小和预排序程度,这种开销可能值得增加速度。
一篇关于Splaysort的论文已经在《软件--实践与经验》杂志上发表。
如果元素已经排序或者只有很少的元素,插入排序将是一个完美的使用案例!
插入排序的时间复杂度为O (n + 逆序对数量)。
逆序对是一对“ (i,j)”,其中 i < j 且 a [i]> a [j] 。也就是说,这是一个无序的配对。
衡量“几乎有序”的一种方法是逆序对的数量——“几乎有序数据”可以理解为具有较少逆序对的数据。例如,如果人们知道逆序对的数量是线性的(例如,您只向排序列表中添加了 O(1) 个元素),则插入排序的时间复杂度为O(n)。