哪种排序算法最适合大多数排序数据?

时间:2008-10-20 21:38:24

标签: algorithm sorting

哪种排序算法最适合大多数排序数据?

20 个答案:

答案 0 :(得分:248)

基于高度科学的观察方法animated gifs我会说插入和冒泡是很好的候选人。

答案 1 :(得分:102)

只有少数项目=> INSERTION SORT

项目大部分已经排序=> INSERTION SORT

关注最坏情况=> HEAP SORT

对良好的平均案例结果感兴趣=> QUICKSORT

项目来自密集的宇宙=> BUCKET SORT

希望尽可能少编写代码=> INSERTION SORT

答案 2 :(得分:30)

timsort

Timsort是“一种适应性,稳定,自然的融合”,“超自然的表现 各种部分有序的数组(少于lg(N!)比较,和 只有N-1)“。Python的内置sort()已经使用了这个算法一段时间,显然效果很好。它专门用于检测和利用输入中部分排序的子序列,这些子序列经常发生在真实数据集中。在现实世界中通常情况下,比较比在列表中交换项目要昂贵得多,因为通常只是交换指针,这通常使得timsort成为一个很好的选择。但是,如果你知道你的比较总是非常便宜(编写一个玩具程序来排序32位整数),其他算法可能会表现得更好。利用timsort的最简单方法当然是使用Python,但是因为Python是开放的您可能也可以借用代码。或者,上面的描述包含了足够的详细信息来编写您自己的实现。

答案 3 :(得分:19)

具有以下行为的插入排序:

  1. 对于广告位k中的每个元素1..n,请先检查el[k] >= el[k-1]。如果是这样,请转到下一个元素。 (显然跳过第一个元素。)
  2. 如果没有,请在元素1..k-1中使用二进制搜索来确定插入位置,然后将元素移过。 (只有在k>T T为某个阈值的情况下才可以执行此操作;如果k为小{{1}},这可能是过度的。)
  3. 此方法进行的比较次数最少。

答案 4 :(得分:11)

尝试内省排序。 http://en.wikipedia.org/wiki/Introsort

它基于quicksort,但它避免了quicksort对近乎排序的列表的最坏情况行为。

技巧是这种排序算法检测快速排序进入最坏情况模式并切换到堆或合并排序的情况。通过一些非naiive分区方法检测几乎排序的分区,并使用插入排序处理小分区。

您可以获得所有主要排序算法中最好的代码,以获得更多代码和复杂性。无论您的数据如何,您都可以确定自己永远不会遇到最坏的情况。

如果您是C ++程序员,请检查您的std :: sort算法。它可能已在内部使用内省排序。

答案 5 :(得分:7)

Splaysort是一种基于splay trees的模糊排序方法,paper on splaysort是一种自适应二叉树。 Splaysort不仅适用于部分排序的数据,还适用于部分反向排序的数据,或者实际上任何具有任何预先存在的顺序的数据。在一般情况下是O(nlogn),在数据以某种方式(正向,反向,器官管道等)排序的情况下是O(n)。

它优于插入排序的优势在于,当数据完全没有排序时,它不会恢复为O(n ^ 2)行为,因此您无需绝对确定数据是否已部分排序在使用之前。

它的缺点是它需要的splay树结构的额外空间开销,以及构建和销毁splay树所需的时间。但是,根据您预期的数据大小和预先排序的数量,开销速度可能是值得的。

{{3}}发布于Software - Practice&经验。

答案 6 :(得分:5)

插入或shell排序!

答案 7 :(得分:5)

Dijkstra的smoothsort对已排序的数据非常有用。它是一个以O(n lg n)最坏情况和O(n)最佳情况运行的超级变体。我wrote an analysis算法,如果你好奇它是如何工作的。

自然mergesort是另一个非常好用的 - 它是一个自下而上的mergesort变体,它通过将输入视为多个不同排序范围的串联,然后使用合并算法将它们连接在一起来工作。重复此过程,直到所有输入范围都已排序。如果数据已经排序并且O(n lg n)最坏情况,则在O(n)时间内运行。它非常优雅,但在实践中它并不像Timsort或smoothsort等其他自适应排序那么好。

答案 8 :(得分:3)

插入排序需要时间O(n +反转次数)。

反转是一对(i, j)i < j && a[i] > a[j]。也就是说,是一个无序对。

“几乎排序”的一个衡量标准是反转次数 - 人们可以将“几乎已排序的数据”视为具有很少反转的数据。如果知道反转的数量是线性的(例如,您刚刚将O(1)元素附加到排序列表),则插入排序需要O(n)时间。

答案 9 :(得分:3)

如果元素已经排序或者元素很少,  这将是Insertion Sort的完美用例!

答案 10 :(得分:2)

我不打算假装在这里得到所有答案,因为我认为得到实际答案可能需要编码算法并根据代表性数据样本进行分析。但是我整个晚上一直在考虑这个问题,到目前为止,这是我发生的事情,还有一些关于什么最有效的猜测。

设N为项目总数,M为无序数。

冒泡排序必须使2 * M + 1次通过所有N项。如果M非常小(0,1,2?),我认为这将很难被击败。

如果M很小(比如小于log N),插入排序将具有很高的平均性能。然而,除非有一个我没有看到的技巧,否则它将会有非常糟糕的最坏情况表现。 (对吗?如果顺序中的最后一项是第一个,那么你必须插入每一个项目,据我所知,这会破坏性能。)我猜这里有一个更可靠的排序算法案件,但我不知道它是什么。

如果M更大(比等于或大于log N),内省排序几乎肯定是最好的。

所有这些的例外情况:如果您事先确实知道哪些元素未排序,那么您最好的选择是将这些项目拉出来,使用内省排序对它们进行排序,并将两个排序列表合并为一个排序列表。如果您能够快速找出哪些项目无序,这也是一个很好的通用解决方案 - 但我还没有找到一种简单的方法来做到这一点。

进一步的想法(一夜之间):如果M + 1&lt; N / M,然后您可以扫描列表,查找已排序的N / M行,然后在任一方向上展开该行,以查找无序项。这最多需要2N次比较。然后,您可以对未排序的项进行排序,并在两个列表上执行排序合并。我认为,总比较应该小于4N + M log2(M),这将打败任何非专业的排序程序。 (更进一步的想法:这比我想的要复杂,但我仍然认为这是合理可能的。)

对该问题的另一种解释是,可能存在许多无序项目,但它们非常接近列表中应该存在的位置。 (想象一下,从排序列表开始,并将每个其他项目与之后的项目进行交换。)在这种情况下,我认为冒泡排序表现非常好 - 我认为通过次数与最远的项目成正比是。插入排序效果不佳,因为每个乱序项都会触发插入。我怀疑内省排序或类似的东西也能很好地运作。

答案 11 :(得分:2)

正如其他人所说,小心天真的Quicksort - 对排序或接近排序的数据可以有O(N ^ 2)性能。尽管如此,通过选择枢轴的适当算法(随机或三个中位数 - 见Choosing a Pivot for Quicksort),Quicksort仍然可以正常工作。

一般来说,选择插入排序等算法的难度在于决定数据何时足够乱序,Quicksort真的会更快。

答案 12 :(得分:1)

如果您需要针对排序算法,数据结构或任何具有上述链接的任何内容的特定实现,我可以向您推荐CodePlex上的优秀"Data Structures and Algorithms"项目吗?

如果不重新发明轮子,它将拥有您需要的一切。

只是我的一点点盐。

答案 13 :(得分:1)

这个很好的排序算法集合在答案中用于此目的,似乎缺少Gnome Sort,这也是合适的,并且可能需要最少的实现工作。

答案 14 :(得分:0)

思考尝试堆。我相信这是O(n lg n)种类中最一致的。

答案 15 :(得分:0)

冒泡排序(或更安全但双向冒泡排序)可能是大多数排序列表的理想选择,但我敢打赌,当调整时,调整梳子排序(具有低得多的初始间隙大小)会更快一些列表不是那么完美排序。梳子排序降级为冒泡排序。

答案 16 :(得分:0)

插入排序是排序输入的最佳情况O(n)。并且它在大多数排序输入上非常接近(比快速排序更好)。

答案 17 :(得分:0)

这取决于用例。如果您知道更改了哪些元素,就我而言,删除和插入将是最好的情况。

答案 18 :(得分:0)

冒泡排序绝对是赢家 雷达上的下一个是插入排序。

答案 19 :(得分:-1)

远离QuickSort - 对预先排序的数据效率非常低。插入排序通过移动尽可能少的值来处理几乎排序的数据。