【问题标题】:How to modify QuickSort such that pivot is at its correct position如何修改快速排序以使枢轴处于正确位置
【发布时间】:2017-01-04 23:19:07
【问题描述】:

考虑如下数组,

int[] a = {100, 1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15, 16};

考虑到中间元素总是作为轴心。

pivot = 10

标准的快速排序算法如下所示

public void quickSort(int[] a, int low, int high) {
        if (a == null || a.length == 0)
                return;

        if (low >= high)
                return;

        int pivotIndex = partition( a, low, high );
        quickSort(a, low, pivotIndex-1);
        quickSort(a, pivotIndex, high);
    }

    public int partition ( int[] a, int low, int high )
    {
        // pick the pivot
        int middle = low + (high - low) / 2;
        int pivot = a[middle];

        while (low <= high) {
            while (a[low] < pivot) {
                    low++;
            }

            while (a[high] > pivot) {
                    high--;
            }

            if (low <= high) {
                    swap( a, low, high );
                    low++;
                    high--;
            }
        }

        return low;
    }

在完成一次 while 循环的迭代后(围绕 10 旋转),数组如下所示

 high          low 
  10 1 2 3 4 5 100 11 12 13 14 15 16

如您所见,枢轴元素位于索引 0 处,这不是 10 的正确位置。

我的问题是,我怎样才能修改上述算法,以便在每次迭代结束时,枢轴元素位于正确的位置,并且我们继续递归左右两半而不考虑枢轴

【问题讨论】:

  • 看起来有点像家庭作业问题。答案也很明显。也许您应该让我们知道,根据您的说法,正确的做法是什么。我们可以从那里拿走它。
  • 该问题询问有关 while 循环的一次迭代。在 while 循环完成所有迭代之前(当示例代码中的低 > 高时),枢轴不应该最终处于正确位置。分区代码可能需要一个小的修复。示例代码类似于Hoare partition scheme,在这种情况下,枢轴将最终位于左侧或右侧分区中。可以添加代码来排除枢轴和等于枢轴值的相邻元素。
  • 当我复制副本并在我的环境中测试时,看起来工作正常。
  • @rcgldr,但是为什么在 while 循环完成所有迭代之前,枢轴不应该在正确的位置结束。如果可以那样做的话,算法会更有意义。你确定不能做吗?
  • @Quirk,绝对不是功课。我有我的想法,但没有把它放在这里,因为我不想影响答案。但是在这里,我所要求的原因没有发生,因为我们在交换之后盲目地做低++和高。应该避免这种情况,因为低或高可能是枢轴的正确位置,但是通过执行低++或高--,我们放弃了这一点。让我知道你会怎么做。

标签: java algorithm sorting quicksort


【解决方案1】:

如果目标是在开始时在其(它们的)正确位置获取枢轴值,则代码可以对数组进行单次扫描,检查小于、等于或大于枢轴的值,例如生成三个计数:ltpivot = # elements pivot value。 (通过扫描只需要生成两个计数,第三个计数将是(高 + 1 - 低 - (计数中的 2 个))。然后所有枢轴值应移动到索引位置低 + ltpivot 到低 + ltpivot + eqpivot - 1. 这可以通过另一遍将枢轴值交换到位。然后可以进行第三遍将小于或大于枢轴的元素交换到枢轴的左侧或右侧。

问题在于,这种方法比标准快速排序要慢,需要对数组进行 3 次扫描,而标准快速排序实际上是一次扫描。标准快速排序只会正确放置一个枢轴元素,而将任何其他元素 == 枢轴分散,但在典型情况下,这不是问题。 (标准快速排序的最坏情况之一是所有值都相同)。

【讨论】:

  • “标准快速排序只会正确放置一个枢轴元素”。请看我上面的例子,我什至没有看到一个元素被放置在正确的位置。 10 是第一次迭代中的枢轴,没有放置在正确的位置。
  • 能否请您指出您所说的“标准快速排序”实现。我对“标准快速排序”的引用是上面实现的,正如我所说,10 在迭代结束时不在正确的位置。它应该是索引 5,而这个算法将它放在索引 0 处。
  • 如果您能向我指出您正在谈论的这个实现的一个网络链接,那将是非常棒的,我可以调试并看看它是如何工作的。几乎所有我可以用谷歌搜索的东西都带有一段时间(低
  • @PepperBoy - 我删除了我之前的 cmets。使用示例代码中的后递减和后递增分区函数,while (low Hoare partition scheme 的 wiki 示例使用 pre-increment 和 pre-decrement 。枢轴值不必是 A[lo],它可以是数组中的任何值,例如中间的 A[(lo + hi)/2]。
猜你喜欢
  • 2014-12-23
  • 2011-08-31
  • 2017-02-25
  • 1970-01-01
  • 2015-01-13
  • 2010-09-14
  • 2020-03-15
  • 2012-12-20
  • 1970-01-01
相关资源
最近更新 更多