如何对三个快速排序的中值进行最坏情况排列

How to make worst case permutation of median of three quicksort

本文关键字:最坏 排列 情况 快速排序 三个      更新时间:2023-10-16

我知道快速排序的时间复杂度。但我想知道如何创建最坏情况排列。

我想这是有规则的。我真的想了很多,但对我来说太难了。

请告诉我如何为三个快速排序的中位数创建最坏情况,而不仅仅是普通快速排序。(例如,如果枢轴是列表中最左边的项,列表的最坏情况排列是有序列表,但如果枢轴是三个的中位数呢?)

这是我的快速排序算法代码

不幸的是,没有通用的答案,因为它取决于"三的中位数"部分是如何实现的,以及"划分"步骤是如何实现的。如果给它们大量相同的元素,它们很容易陷入最坏的情况。但对于更有趣的情况,一般概念是这样的。

从数字1....开始N,以及一个大小相同的"未知数组"。你还不知道哪个数字在哪个索引中。

  1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20
[ A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T]

对于快速排序来说,最糟糕的情况是当选择的枢轴尽可能靠近一端时,所以你想要三个元素中最大(或最小)的三个元素作为中位数。通常是(但不总是)第一个、中间和最后一个元素。

  1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17
[19, B, C, D, E, F, G, H, I,18, K, L, M, N, O, P, Q, R, S,20]
现在我们知道,在分区步骤之后,数组可能会看起来像这样,这取决于分区是如何实现的:
[ S, B, C, D, E, F, G, H, I,18, K, L, M, N, O, P, Q, R,19,20]
                                                       ^ pivot

然后它将递归到[18-R]子部分。(它可能会也可能不会在[20]分段上额外递归,但我们在那里不能做更多的事情。所以我们重复这个模式,把接下来的两个最大的元素放在剩下的元素的末尾和中间:

[16, B, C, D, E, F, G, H,15,18, K, L, M, N, O, P, Q,17]

分区后,它看起来像:

[ P, B, C, D, E, F, G, H,15, Q, K, L, M, N, O,16,18,17]
                                               ^ pivot

然后我们继续处理下一小节:

[ P, B, C, D, E, F, G, H,15, Q, K, L, M, N, O]

请注意,当我们填充"最大"元素时,我们将数组位置(字母)替换为数字。当我们完成后,我们就会知道每个数组位置对应的数字。到目前为止,我有这个:

[19, B, C, D, E, F, G, H,15,18, K, L, M, N, O, P, Q,17,19,20]

不幸的是,正如我所提到的,它在很大程度上取决于如何选择主节点以及如何实现分区。可能存在一个简单的模式,你可以填充,但我不知道它会是什么。您还会注意到,我总是将前三个的中位数放在最左边,因为这使大多数分区实现的行为更相似,但实际上,如果您知道分区是如何工作的,可能最好将前三个的中位数放在另外两个可能的位置之一,只是为了让它多做一次交换。

创建一种会导致所有甚至大多数快速排序实现表现出最坏情况的项目排列是不可能的。事实上,这取决于排序是如何实现的,在一次运行中最坏情况下的数组可能在下一次运行中还可以。如果实现使用随机- 3的中位数来选择枢轴,并且每次调用例程时使用不同的种子,则可能发生这种情况。

C qsort函数和许多其他库中的排序库函数容易受到"快速排序杀手"算法的攻击,该算法使用比较回调中提供的信息动态创建最坏的情况。令人惊讶的是,这并不难做到。例如,参见快速排序的杀手对手。