QuickSort最糟糕的情况 – 何时会发生?
在分析QS时,每个人总是指“几乎sorting”的最坏情况。 什么时候自然input会出现这种情况?
我提出的唯一例子是重新编制索引。
我认为人们混淆Quicksort基于分区的sortingalgorithm,并“qsort”各种库实现。
我更喜欢将Quicksortalgorithm看作具有可插入的数据透视selectalgorithm,这对于分析其行为非常重要。
如果第一个元素总是被选为主元素,那么已经sorting的列表是最差的。 通常数组很可能已经被sorting了,所以这个实现相当糟糕。
类似地,select最后一个元素作为支点也是同样的原因。
一些实现尝试通过select中间元素作为主元来避免这个问题。 这对于已经/接近sorting的数组来说不会那么糟糕,但是仍然可以构build一个input来利用这个可预测的枢轴select,并使它在二次时间内运行。
因此,你会得到随机枢轴selectalgorithm,但即使这样也不能保证O(N log N)
。
所以开发了其他algorithm,可以在select数据透视之前使用序列中的一些信息。 你当然可以扫描整个序列,find中位数,并将其用作关键点。 这保证了O(N log N)
,但是在实践中当然是较慢的。
所以有些angular落被削减,人们devise了3位数的algorithm。 当然,以后甚至可以被所谓的“三分之一杀手”所利用。
所以更多的尝试提出了更多的“智能”枢轴selectalgorithm,以保证O(N log N)
渐近行为仍然足够快,是实用的,并取得了不同程度的成功。
所以真的,除非指定Quicksort的特定实现,否则最坏情况发生的时间是不明确的。 如果使用所谓的中位数中值selectalgorithm,则不存在二次最坏情况。
但是,大多数库实现,可能会放弃O(N log N)
保证,以便在平均情况下更快地进行sorting。 一些非常古老的实现使用第一个元素作为支点,现在这个元素被理解为很差,不再被广泛使用。
我相信,快速sorting的最坏情况取决于在每一步的枢轴元素的select。 如果枢轴很可能是列表中最小或最大的元素(例如,已sorting的列表的第一个或最后一个元素),则Quicksort的性能最差。
例如,如果select列表的中间元素,那么已经sorting的列表不会有最差的运行时间。
所以,如果你怀疑你的场景很可能是快速sorting的情况下,你可以简单地改变你的select枢纽元素,使快速sorting更好地执行。
注:我知道,这并没有给出更多快速sorting最坏情况的真实世界的例子。 这个例子取决于你正在使用的实现。
实际的问题是:“什么时候这种情况(几乎sorting)发生自然input?”。
虽然所有的答案都是在处理“什么原因导致最糟糕的情况”,但没有一个答案是“什么原因导致数据满足最糟糕的情况”。
所以,要回答实际的问题
-
程序员错误 :基本上,你着陆了两次sorting列表。 通常情况下,这是因为列表在代码中sorting一个地方。 在后面的另一段代码中,您知道需要对列表进行sorting,因此您可以再次对其进行sorting。
-
使用几乎按时间顺序排列的数据 :通常按照时间顺序接收数据,但有时候某些元素不在位。 (考虑一个multithreading环境,将时间标记的元素添加到列表中,竞争条件可能会导致元素以不同的顺序添加,这些元素被加上时间戳)。在这种情况下,如果您需要sorting的数据, -分类。 因为数据的顺序不能保证。
-
将项目添加到列表 :如果您有一个sorting列表,并简单地附加一些项目(即不使用二进制插入)。 你将需要重新sorting一个几乎sorting的列表。
-
来自外部来源的数据:如果您收到来自外部来源的数据,则可能无法保证其被sorting。 所以你自己来分类。 但是,如果外部源已sorting,则将重新sorting数据。
-
自然sorting :这与时序数据类似。 基本上,您收到的数据的自然顺序可能会被sorting。 考虑一家保险公司增加汽车登记。 如果驾驶汽车注册的权力按照可预见的顺序进行,新车可能会有, 但不能保证有更高的注册号码。 既然你不能保证它被sorting – 你必须重新sorting。
-
交错数据 :如果您从多个重叠键的sorting源接收数据,您可以得到类似于以下的键:1 3 2 5 4 7 6 9 8 11 10 13 12 15 14 17 16 19 18.即使有一半的元素序列与邻居,名单是“几乎sorting”。 当然,使用第一个元素的QuickSort会显示
O(n^2)
性能。
结论
因此,考虑到上述所有情况,实际上很容易将sorting的数据sorting。 这正是为什么QuickSort实际上最好的避免的原因。 多基因提供了一些关于交替旋转考虑的有趣信息。
作为一个侧面说明:通常performance最差的sortingalgorithm之一,实际上与“几乎sorting”的数据很好。 在上面的交错数据中,冒泡sorting只需要9个交换操作。 它的performance实际上是
O(n)
。
从Quicksort
对于快速sorting,“最坏情况”对应已经sorting
与所有项目相同的号码列表已被sorting 。
最糟糕的情况在快速sorting:
- 数组的所有元素都是相同的
- 数组已按照相同的顺序sorting
- 数组已经按照相反的顺序sorting了。
最坏的情况取决于select枢纽元素。 所以只有当1)数组已经按照相同的顺序sorting时才会出现问题。 2)数组已经按照相反的顺序sorting了。 3)所有元素都是相同的(情况1和2的特例)