是什么造成快速分类的坏情况?


10

我正在学习quicksort,并想说明quicksort很难解决的各种数组。我想到的快速排序没有初始随机改组,没有2分区,并且不计算中位数。

到目前为止,我想到了三个示例:

[1,2,3,4,5,6,7,8,9,10] - when the array is sorted
[10,9,8,7,6,5,4,3,2,1] - when the array is reversed
[1,1,1,1,1,1,1,1,1,1] - when the array is the same values
[1,1,1,2,2,2,3,3,3,3] - when there are few and unique keys

例如,我对此不太确定:

[1,3,5,7,9,10,8,6,4,2]

那么,为什么快速排序的阵列与(几乎)理想的阵列相比有什么困难呢?


2
如何选择支点?您说了没有选择它的两种方式,但没有说到如何选择它。
Winston Ewert 2014年

请给出QuickSort的最坏情况-什么时候发生?在StackOverflow上读取。我还发现sorting.at是排序算法的很好的可视化对象。

@WinstonEwert数据透视由第一个元素选择。
mrQWERTY

@ Renren29我修改的问题有点想动它把重点放在原因为何快速排序将有一个给定的阵列困难,而不是寻求例子阵列(我没有人可以给你答案的[2,1,2,1,2,1,2,1],并且是整个回答)。理想情况下,该问题的目标是使其他人可以来了解原因(有答案)而不是示例(无数个例子)。

您正在运行quicksort到2个元素的块吗?因为现实世界的实现倾向于对小块使用更简单的排序。例如,比较和交换比N = 2的快速排序要简单得多。
MSalters 2014年

Answers:


9

每种排序算法都有最坏的情况,在许多情况下,最坏的情况确实很糟糕,因此值得对其进行测试。问题是,没有一个最坏的情况只是因为您了解基本算法。

常见的最坏情况包括:已经排序;反向排序 几乎排序,一个乱序元素;所有值都相同;除了第一个(或最后一个)更高(或更低)之外,其他所有内容都相同。我们曾经遇到过这样一种情况,其中最坏的情况是特定的锯齿模式,这很难预测,但在实践中相当普遍。

quicksort最坏的情况是使它始终选择最坏的枢轴,因此分区之一只有一个元素。如果支点是第一个元素(错误的选择),那么最坏的情况就是已经排序或反向排序的数据。对于三个中位数的数据透视图来说,这些数据都是相同的,或者只是第一个或最后一个是不同的。


对于快速排序,平均复杂度为nlogn,最坏情况为n ^ 2。值得触发最坏情况的行为的原因是,这也是产生最大递归深度的情况。对于简单的实现,递归深度可以为n,这可能会触发堆栈溢出。由于类似的原因,测试其他极端情况(包括最佳情况)可能是值得的。


我看到了,所以平均值的标准偏差确实决定了划分结果。
mrQWERTY 2014年

“ ...几乎在每种情况下,最坏的情况都是非常糟糕的,因此值得对其进行测试。” 。这值得商.。当我看这张表时:en.wikipedia.org/wiki/…我得出结论,对于大多数 “好的”排序算法(即具有平均O(NlogN)性能或更佳的排序算法),最坏情况和平均情况具有相同的复杂性。这表明通常不值得在最坏的情况下进行测试。(鉴于测试可能是O(N)……或更糟。)
Stephen C

@ Renren29:仅当2个或3个值相同时,3个枢轴的中位数才是第一个或最后一个。SD没有加入。
david.pfx

@StephenC:许多包括快速排序在内的“好的”算法都具有n ^ 2的最坏情况复杂度。但请参阅编辑。
david.pfx

@ david.pfx-“有些” ...是的。“几乎每个”……不。
斯蒂芬·C

0

该算法使用随机枢轴来逃避大多数恶劣情况,不包括等于分割和不对称搜索的枢轴的连续元素。它向前搜索大于或等于枢轴的元素,向后搜索小于枢轴的元素。
感谢MichaelT,非对称搜索旨在解决[2,1,2,1,2,1,2,1]。

我的函数qsort_random()生成以下结果。N = 100,000

usec    call   compare   copy    pattern
80132   62946  1971278   877143  random
47326   57578  1606067   215155  sorted : 0,1,2,3,...,n-1
49927   63578  1628883   338715  sorted in reverse : n-1,n-2,...,2,1,0
55619   63781  1596934   377330  nearly reverse : n-2,n-1,n-4,n-3,...,2,3,0,1
54714   66667  1611454   290392  median-3-killer : n-1,0,1,2,...,n-2
1491    1      99999     4       all values the same : n,n,n,...
1577    1      99999     4       first is higher : n,1,1,1,...
2778    2      156159    10      last is lower : n,n,n,...,n,1
2994    3      199996    100009  a few data : n,...,n,1,...,1
3196    3      199996    50012   zigzag : n,1,n,1,...,n,1
917796  56284  67721985  673356  valley(sawtooth?) : n-1,n-3,...,0,...,n-4,n-2

大多数情况比随机模式要快。对于大多数枢轴选择而言,谷底模式都是不利的情况。

qsort(3)       usec = 14523   call = 0      compare = 884463    copy = 0
qsort_head()   usec = 138609  call = 99999  compare = 8120991   copy = 1214397
qsort_middle() usec = 664325  call = 99999  compare = 52928111  copy = 1036047
qsort_trad()   usec = 118122  call = 99999  compare = 6476025   copy = 1337523
qsort_random() usec = 295699  call = 58806  compare = 19439952  copy = 732962
qsort_log2()   usec = 66411   call = 63987  compare = 1597455   copy = 944821

通过选择log2(N)元素中的枢轴,qsort_log2()可以避免出现不良情况。
qsort(3)使用GNU库,它是索引排序的合并排序。
qsort_trad()在第一个,中间和最后一个元素中选择一个枢轴。
qsort_random()和qsort_log2()不使用交换。
源C程序和脚本发布在github中

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.