📜  快速排序算法的改进

📅  最后修改于: 2021-05-08 17:32:40             🧑  作者: Mango

先决条件: QuickSort算法

在最坏的情况下,本文讨论的快速排序算法可能需要O(N 2 )时间。因此,需要能够有效地划分阵列并围绕枢轴重新布置元件的某些变型。

单轴分区在单轴分区中,数组A []可分为{A [p],A [p + 1],A [p + 2],…,A [r]}分为两部分A [p …q]A [q + 1 … r]这样:

  • 第一分区中的所有元素A [p … q]均小于或等于枢轴值A [q]
  • 第二分区中的所有元素A [q + 1…r]均大于或等于枢轴值A [q]
  • 之后,将两个分区视为独立的输入数组,并将其自身馈入快速排序算法

Lomuto的分区这是最简单的分区过程。从最左边的元素开始,并跟踪较小(或等于)元素的索引为i 。遍历时,如果找到较小的元素,则将当前元素与A [i]交换。否则,请忽略当前元素。

本文将对此进行详细讨论。

Hoare的分区它通过初始化两个从两端开始的索引来工作,两个索引彼此相对移动,直到找到一个反转(左侧的值较小,右侧的值较大)。找到反转后,将交换两个值并重复该过程。 Hoare的分区方案比Lomuto的分区方案效率更高,因为它的交换次数平均减少了三倍,即使所有值都相等,它也可以创建有效的分区。

这里详细讨论了LomutoHoare分区的比较。

随机旋转在以上两种方法中,其思想是获取未探索数组的第一个或最后一个元素,并以该元素作为枢轴来查找该元素在数组中的正确位置。如果数组已经按照升序或降序排序,并且始终选择第一个元素作为枢轴,那么它将始终是未探索的数组元素中的最大或最小元素。它将仅将未探索的数组的大小减小1,从而使快速排序算法执行O(N 2 )的最坏情况下的时间复杂度。

如果我们从未探索的数组中选择一个随机元素并将其与第一个元素交换,然后执行分区过程(上述两个过程中的任何一个),而不是每次都将第一个元素作为枢轴,则可以提高预期的或平均时间复杂度为O(N * log N) 。最坏情况下的复杂度仍然是O(N 2 ) 。虽然,当数组已经排序时,避免了最坏的情况,但是当数组包含许多重复的元素时,最坏的情况就会发生。

要了解随机算法如何提高平均案例时间复杂度,请参阅本文。

重复元素的性能考虑数组arr [] = [3,3,3,3,3,3] ,即数组具有所有(或许多)相等的元素。使用单轴分区方案对该数组进行分区时,我们将获得两个分区。第一个分区将为空,而第二个分区将具有(N – 1)个元素。此外,分区过程的每次后续调用将仅将输入大小减小一个。由于划分过程具有O(N)复杂度,因此总的时间复杂度将为O(N 2 ) 。当输入数组具有许多重复的元素时,这是最坏的情况。

为了减少重复元素数量很多时的最坏情况,而不是单轴分区方案,我们可以实现三向分区方案。

三向分区为了有效地对具有大量重复键的数组进行排序,我们可以在第一次遇到键时将其放置在正确的位置。因此,数组的三向分区由以下三个分区组成:

  • 最左边的分区包含严格小于枢轴的元素。
  • 中间分区包含等于枢轴的所有元素。
  • 最右边的分区包含严格大于枢轴的所有元素。

荷兰国旗(DNF)排序算法相对于给定的枢轴,它可以将数组的所有数字分为三组:

  • 较小”组包含严格小于轴心的所有元素。
  • 等于”组包含等于枢轴的所有元素。
  • 更大的 组包含严格大于枢轴的所有元素。

要解决DNF问题,请选择第一个元素作为枢轴,然后从左到右扫描阵列。在检查每个元素时,我们将其移至正确的组,即LesserEqualGreater

要了解DNF排序算法的实现,请参考本文。

本特利-麦克罗伊(Bentley-McIlroy)的“优化3路分区”该算法是基于迭代的分区方案。数组的所有元素最初都是未开发的。从左右方向开始探索数组的元素。每次迭代后,可以将数组可视化为五个区域的组合:

  • 极端的两个末端是具有等于枢轴值的元素的区域。
  • 未开发的区域停留在中心,并且每次迭代都在不断缩小。
  • 在未探索区域的左侧是小于枢轴值的元素。
  • 在未探索区域的右侧是大于枢轴值的元素。

随着迭代过程的继续,数组的未探索区域不断减少,最后,数组将没有剩余的未探索元素。

现在,由于元素相等 到枢轴元素大于小于区域中的元素小于大于较大区域中的元素 区域,则需要将它们移至较小区域和较大区域之间的中心。通过与较小区域和较大区域的元素交换来将它们带到中心。

最后,问题减少了,再次使用相同的方法在较小和较大的区域中对元素进行排序,直到对整个数组进行排序为止。

三向划分的分析通常,快速排序算法的平均情况下时间复杂度为O(N * log(N)),最坏情况下的时间复杂度为O(N 2 ) 。使用大量重复的键,通过快速排序的简单实现,我们总是获得最差的性能。

但是,使用三向分区可以减少大量重复密钥的影响。实际上,具有所有元素的数组在单轴分区中按O(N 2 )时间排序,而在三向分区中按O(N) (线性)时间复杂度排序。因此,过去最差的情况变成了三路分区的最佳情况。