如何在QuickSort中选择透视值?

时间:2016-12-16 10:26:37

标签: arrays sorting quicksort

我一直在研究几个小时的快速排序,并对选择一个支点值感到困惑。数组中是否需要存在透视值?

例如,如果数组是1,2,5,6,我们可以使用值3或4作为轴吗?

我们使用pivot的位置将数组划分为子数组,但是在移动值之后我对于枢轴位置有点困惑<数组左侧的数值和值> 5到对吗?

7,1,5,3,3,5,8,9,2,1

我用枢轴5干了算法,并得出以下结果:

1,1,5,3,3,5,8,9,2,7
1,1,5,3,3,5,8,9,2,7
1,1,5,3,3,5,8,2,9,7

我们可以看到值2仍然不在正确的位置。我究竟做错了什么?对不起,如果这是一个愚蠢的问题。

我提出了以下代码,但它只在pivot = left时工作,我无法使用随机数据透视。

template <class T>
void quickSort(vector <T> & arr, int p, int r, bool piv_flag) {
    if (p < r) {
        int q, piv(p); counter++;

        //piv = ((p + r) / 2); doesn't work

        q = partition(arr, p, r, piv);
        quickSort(arr, p, q - 1, piv_flag); //Sort left half
        quickSort(arr, q + 1, r, piv_flag); //Sort right half
    }

    return;
}

int partition(vector <T> & arr, int left, int right, int piv) {
    int i{ left - 0 }, j{ right + 0 }, pivot{ arr[piv] };

    while (i < j) {
        while (arr[i] <= pivot) { i++; }
        while (arr[j] > pivot) { j--; }
        if (i < j) (swap(arr[i], arr[j]));
        else {
            swap(arr[j], arr[piv]);
            return j;
        }
    } 
}

谢谢。

1 个答案:

答案 0 :(得分:1)

在许多应用程序中,pivot被选为数组中的某个元素,但它也可以是您可以用来将数组中的数字分成两个的任何值。如果您选择的数据透视值是数组中的特定元素,则在将数组分割为两个后,需要将它放在这两个组之间。如果没有,您可以通过正确调用索引来继续进行递归排序过程。 (即记住数组中没有枢轴元素,只有两组值)

请参阅this response一个类似的问题,以简要解释一些广泛使用的选择枢轴的替代方案。

枢轴最重要的功能是充当我们在快速排序的分区阶段尝试创建的组之间的边界。这里的目标/挑战是以这样的方式创建这些组,使它们在大小上相等或几乎相等,以便快速排序可以有效地工作。这个挑战是构思如此多的枢轴选择方法的原因。 (即至少在大多数情况下,数字将被分成相似大小的组)

关于分区完成后枢轴位置如何变化的问题的第二部分,请参阅下面的样本分区阶段。

假设我们有一个带有元素[4,1,5,3,3,5,8,9,2,1]的数组A,我们选择了pivot作为第一个元素,即4.下面使用的字母E表示小于枢轴的元素的结尾。 (即小于枢轴的最后一个元素)

String.valueOf(randNum)

在此分区之后,显然仍然没有对元素进行排序。但是4左边的所有元素都小于4,右边的所有元素都大于4.要对它们进行排序,我们递归地在这些组上使用Quicksort。

根据您的代码,下面是基于我上述过程的示例分区代码。您可能还会观察其执行情况here

   E
[4,1,5,3,3,5,8,9,2,1]

     E
[4,1,3,5,3,5,8,9,2,1]

       E
[4,1,3,3,5,5,8,9,2,1]

         E
[4,1,3,3,2,5,8,9,5,1]

           E
[4,1,3,3,2,1,8,9,5,5]

[1,1,3,3,2,4,8,9,5,5] // swap pivot with the rightmost element that is smaller than its value