我在一次面试中被问到这个问题。它们都是O(nlogn),但大多数人使用快速排序而不是归并排序。为什么呢?


当前回答

正如其他人所注意到的,快速排序的最坏情况是O(n²),而归并排序和堆排序则停留在O(nlogn)。然而,在平均情况下,这三个都是O(nlogn);所以它们在大多数情况下是可比较的。

平均而言,快速排序更好的地方在于,内循环意味着将多个值与单个值进行比较,而在其他两个循环中,每次比较时两个项都是不同的。换句话说,Quicksort的读取次数是其他两种算法的一半。在现代cpu上,访问时间在很大程度上决定了性能,因此快速排序最终成为一个很好的首选。

其他回答

这是采访中经常被问到的一个问题,尽管归并排序在最坏情况下性能更好,但快速排序被认为比归并排序更好,特别是对于大输入。以下是快速排序更好的原因:

1-辅助空间:快速排序是一种就地排序算法。就地排序意味着执行排序不需要额外的存储空间。另一方面,归并排序需要一个临时数组来归并已排序的数组,因此它并不到位。

2-最坏情况:快速排序O(n^2)的最坏情况可以通过使用随机化快速排序来避免。通过选择正确的枢轴,可以很容易地避免这种情况。通过选择合适的枢轴元来获得平均情况下的行为,从而提高了算法的性能,达到了与归并排序一样的效率。

3-引用的局部性:快速排序特别展示了良好的缓存局部性,这使得它在许多情况下比归并排序更快,比如在虚拟内存环境中。

4-尾递归:快速排序是尾递归,而归并排序不是。尾递归函数是一种函数,其中递归调用是函数执行的最后一件事。尾递归函数被认为比非尾递归函数更好,因为尾递归可以被编译器优化。

与归并排序不同,快速排序不使用辅助空间。而归并排序使用辅助空间O(n)。 归并排序的最坏情况时间复杂度是O(nlogn)而快速排序的最坏情况复杂度是O(n²)这发生在数组已经排序的时候。

快速排序是最坏情况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.

在c/c++领域,当不使用stl容器时,我倾向于使用快速排序,因为它是构建的 进入运行时,而归并排序没有。

所以我相信,在许多情况下,这只是阻力最小的途径。

此外,对于整个数据集不适合工作集的情况,快速排序的性能可以高得多。

同时考虑时间和空间的复杂性。 归并排序: 时间复杂度:O(nlogn), 空间复杂度:O(nlogn)

快速排序: 时间复杂度:O(n²), 空间复杂度:O(n)

现在,他们各自在一个场景中获胜。 但是,使用随机枢轴,您几乎总是可以将快速排序的时间复杂度降低到O(nlogn)。

因此,在许多应用中,快速排序是首选,而不是归并排序。