我在一次面试中被问到这个问题。它们都是O(nlogn),但大多数人使用快速排序而不是归并排序。为什么呢?
当前回答
正如其他人所注意到的,快速排序的最坏情况是O(n²),而归并排序和堆排序则停留在O(nlogn)。然而,在平均情况下,这三个都是O(nlogn);所以它们在大多数情况下是可比较的。
平均而言,快速排序更好的地方在于,内循环意味着将多个值与单个值进行比较,而在其他两个循环中,每次比较时两个项都是不同的。换句话说,Quicksort的读取次数是其他两种算法的一半。在现代cpu上,访问时间在很大程度上决定了性能,因此快速排序最终成为一个很好的首选。
其他回答
我想补充的是,到目前为止提到的三种算法(归并排序,快速排序和堆排序)只有归并排序是稳定的。也就是说,对于那些具有相同键的值,顺序不会改变。在某些情况下,这是可取的。
但是,说实话,在实际情况下,大多数人只需要良好的平均性能和快速排序…快速=)
所有排序算法都有其起伏。有关排序算法的概述,请参阅维基百科的文章。
快速排序具有更好的平均情况复杂度,但在某些应用中它是错误的选择。快速排序容易受到拒绝服务攻击。如果攻击者可以选择要排序的输入,他可以很容易地构造一个时间复杂度为o(n^2)的最坏情况的集合。
归并排序的平均情况复杂性和最坏情况复杂性是相同的,因此不会遇到相同的问题。归并排序的这一特性也使它成为实时系统的最佳选择——确切地说,因为没有导致它运行得非常非常慢的病理情况。
由于这些原因,我更喜欢归并排序,而不是快速排序。
虽然它们都在相同的复杂度类中,但这并不意味着它们都具有相同的运行时。快速排序通常比归并排序更快,因为它更容易编写紧凑的实现代码,它所做的操作也更快。这是因为快速排序通常更快,人们使用它而不是归并排序。
然而!我个人经常会使用归并排序或快速排序变体,当快速排序表现不佳时,它们会降级为归并排序。记住。快速排序平均只有O(n log n)最坏情况是O(n²)归并排序总是O(n log n).在实时性能或响应性是必须的情况下,你的输入数据可能来自恶意来源,你不应该使用简单的快速排序。
维基百科上关于快速排序的词条:
Quicksort also competes with mergesort, another recursive sort algorithm but with the benefit of worst-case Θ(nlogn) running time. Mergesort is a stable sort, unlike quicksort and heapsort, and can be easily adapted to operate on linked lists and very large lists stored on slow-to-access media such as disk storage or network attached storage. Although quicksort can be written to operate on linked lists, it will often suffer from poor pivot choices without random access. The main disadvantage of mergesort is that, when operating on arrays, it requires Θ(n) auxiliary space in the best case, whereas the variant of quicksort with in-place partitioning and tail recursion uses only Θ(logn) space. (Note that when operating on linked lists, mergesort only requires a small, constant amount of auxiliary storage.)
快速排序是最坏情况O(n²),然而,平均情况始终执行归并排序。每个算法都是O(nlogn),但你需要记住,当谈论大O时,我们忽略了较低的复杂度因素。当涉及到常数因子时,快速排序比归并排序有显著的改进。
归并排序也需要O(2n)内存,而快速排序可以就地完成(只需要O(n))。这是快速排序通常比归并排序更受欢迎的另一个原因。
额外信息:
快速排序的最坏情况发生在枢轴选择不佳时。考虑下面的例子:
[5, 4, 3, 2, 1]
If the pivot is chosen as the smallest or largest number in the group then quick sort will run in O(n^2). The probability of choosing the element that is in the largest or smallest 25% of the list is 0.5. That gives the algorithm a 0.5 chance of being a good pivot. If we employ a typical pivot choosing algorithm (say choosing a random element), we have 0.5 chance of choosing a good pivot for every choice of a pivot. For collections of a large size the probability of always choosing a poor pivot is 0.5 * n. Based on this probability quick sort is efficient for the average (and typical) case.