【问题标题】:Quick Sort - Median-of-Three pivot selection - Some elements out of order快速排序 - 三轴中位数选择 - 一些元素乱序
【发布时间】:2020-04-30 12:32:23
【问题描述】:

我已经尽我所能实现了我教科书中的快速排序算法,其中包含三个枢轴选择函数的中值 - 数据抽象和问题解决,Walls and Mirrors 第 7 版。它部分工作 - 除了数组中元素的结果并非全部按正确的升序排列。由于某种原因,在某些数字序列以正确的顺序放置后,突然一些整数将在他们自己的间隔中出现乱序,然后它将恢复为之后​​以正确的升序继续,然后再次以一些无序的整数重复。我一直遵循教科书,并且搜索了许多其他解决方案,并注意到了一些细微的差异(例如,我的枢轴选择功能需要 3 个参数,而我见过的所有其他功能需要两个参数)。我试图弄清楚它无济于事,我认为这在逻辑上是次要的,我似乎无法从文本中的伪代码中推断出来。

template<typename ItemType>
void sortFirstMiddleLast(ItemType theArray[], int first, int middle, int last) {

    ItemType temp, temp2, temp3;

    if (theArray[first] > theArray[middle]) {

        temp = theArray[first];
        theArray[first] = theArray[middle];
        theArray[middle] = temp;

    }
    if (theArray[middle] > theArray[last]) {

        temp2 = theArray[last];
        theArray[last] = theArray[middle];
        theArray[middle] = temp2;
    }
    if (theArray[first] > theArray[middle]) {

        temp3 = theArray[first];
        theArray[first] = theArray[middle];
        theArray[middle] = temp3;

    }
}
template<typename ItemType>
int partition(ItemType theArray[], int first, int last)
{
    ItemType temp;

    //Choose pivot and reposition it
    int mid = first + (last - first) / 2;

    sortFirstMiddleLast(theArray, first, mid, last);

    //Interchange
    temp = theArray[last - 1];
    theArray[last - 1] = theArray[mid];
    theArray[mid] = temp;

    int pivotIndex = last - 1;
    ItemType pivot = theArray[pivotIndex];

    //Determine the regions S sub 1 and S sub 2
    int indexFromLeft = first + 1;
    int indexFromRight = last - 2;


    bool done = false;

    while (!done) {

        //locate first entry on left that is >= pivot
        while (theArray[indexFromLeft] < pivot)
            indexFromLeft = indexFromLeft + 1;
        //locate first entry on right that is <= pivot 
        while (theArray[indexFromRight] > pivot)
            indexFromRight = indexFromRight - 1;
        //now indexFromLeft has a new index subscript and indexFromRight has a new index subscript
        //compare the two indexes 
        if (indexFromLeft < indexFromRight) {

            ItemType temp2 = theArray[indexFromRight];
            theArray[indexFromRight] = theArray[indexFromLeft];
            theArray[indexFromLeft] = temp2;
            indexFromLeft = indexFromLeft + 1;
            indexFromRight = indexFromRight - 1;

        }
        else
            done = true;
    }
    //Place pivot in proper position between Ssub1 and Ssub2 and mark its new location
    pivot = theArray[pivotIndex];
    theArray[pivotIndex] = theArray[indexFromLeft];
    theArray[indexFromLeft] = pivot;
    pivotIndex = indexFromLeft;

    return pivotIndex;

}
template<typename ItemType>
void quickSort(ItemType theArray[], int first, int last) {
    //sift out small arrays 

    int n = last - first + 1;

    if ( n < MIN_SIZE){//array is of size < 10 so use insertion sort

        insertionSort(theArray, n);

    }
    else {
        //Make the partition : S1 | Pivot | S2
        int pivotIndex = partition(theArray, first, last);

        //Sort subarrays S1 and S2
        quickSort(theArray, first, pivotIndex - 1);
        quickSort(theArray, pivotIndex + 1, last);

    }

}
const int RAND_NUMSIZE = 51; // for quick sort array size (random number gen 1-50)
const int MIN_SIZE = 10;//specify size of smallest array to use quick sort

int main()
{
int array5[RAND_NUMSIZE] = { 50, 41, 45, 43, 48, 40, 47, 42, 46, 49, 44, 39, 31, 37, 35, 33, 32, 38, 33, 34, 30, 36, 21, 29, 20, 22, 28, 23, 27, 24, 26, 25, 19, 13, 18, 14, 17, 15, 16, 12, 10, 11, 7, 8, 1, 4, 2, 6, 3, 9, 5 }

    std::cout << "\nThe quick sort array before sorting: \n";
    for (int i = 0; i < RAND_NUMSIZE; i++) {
        std::cout << array5[i] << ' ';
    }
    //call quick sort
    quickSort(array5, 0, RAND_NUMSIZE - 1);
    std::cout << "\nThe quick sort array after sorting: \n";
    for (int i = 0; i < RAND_NUMSIZE; i++) {
        std::cout << array5[i] << ' ';
    }

显示我正在谈论的结果的图片链接:

quickSort console output

【问题讨论】:

  • 除了,数组中元素的结果并非都按正确的升序排列。 -- 这是一个很大的except。你的排序不是排序。 我试图弄清楚它无济于事, -- 使用编译器附带的调试器,单步执行程序,直到你看到程序做了一些意想不到的事情。
  • 其次,排序 5 或 6 个数字,而不是 51 个数字。如果您不能对 5 或 6 个数字进行排序,那么您将不会对 51 个数字进行排序。对这么多数字进行排序会让你忘记正在发生的事情。用最少的元素找出导致错误的顺序。然后专注于较小的值序列。
  • 感谢 Paul 的洞察力,我将数组减少到约 10 个元素,结果相同......前几个数字的顺序正确,然后发生了无序的 int 序列。我在想我必须做一个 for 循环来遍历数组并将 if 子句嵌套在我的 sortFirstMiddleLast 函数中。
  • 要查看问题所在,请选择数组中的第一个数字作为基准,而不是三的中位数。当你这样做时,排序是否有效?如果是这样,那么快速排序的基础是好的,而你的枢轴选择策略是不正确的。如果当您仅选择第一个值作为基准时排序不起作用,那么是您的排序例程有问题(并且有很多用 C++ 编写的快速排序实现可用作参考)。
  • 想通了...我的快速排序函数中发生了错误..我的基本情况没有按应有的方式实现,因此它仍在尝试对无法使用的数组大小使用递归.我将其纠正为对大小小于 4 的子数组进行排序,而无需使用分区函数或快速排序递归,仅使用 sortFirstMiddleLast 即可。我应该回答我自己的问题还是删除它?这是我第一次这样做,我注意到我的代表已经出错了。

标签: c++ arrays sorting quicksort median


【解决方案1】:

一旦我在快速排序函数中更正了基本情况的实现,问题就解决了,而不是使用插入排序,而是在将 MIN_SIZE 的 const 值设置为 4 后调用了 sortFirstMiddleLast,因此使用枢轴选择函数对 3 进行排序条目而不是通过尝试对小子数组使用分区和递归来导致逻辑错误..

template<typename ItemType>
void quickSort(ItemType theArray[], int first, int last) {
    //relegate out small arrays 

    int n = last - first + 1;//index range of elements to consider

    int middle = first + (last - first) / 2;

    if ( n < MIN_SIZE){//array is of size < 4 so no partition or quick sort

        sortFirstMiddleLast(theArray, first, middle, last);//base case

    }
    else {
        //Make the partition : S1 | Pivot | S2
        int pivotIndex = partition(theArray, first, last);

        //Sort subarrays S1 and S2
        quickSort(theArray, first, pivotIndex - 1);
        quickSort(theArray, pivotIndex + 1, last);

    }


}

【讨论】:

    【解决方案2】:

    我认为您的quickSort() 有问题:

    if (n < MIN_SIZE) { //array is of size < 10 so use insertion sort
        insertionSort(theArray, n);
    }
    

    当你有一个小分区时,你总是插入排序theArray的第一个n元素。

    您实际上想要对从firstlast 的范围进行排序。您可以通过传递指向theArray[first] 的指针和像这样的小分区大小来做到这一点:

    if (n < MIN_SIZE) { //array is of size < 10 so use insertion sort
        insertionSort(theArray + first, n);
    }
    

    当然,您要确保插入排序也是正确的...

    【讨论】:

      猜你喜欢
      • 2019-11-23
      • 2010-09-14
      • 2014-12-23
      • 1970-01-01
      • 1970-01-01
      • 2017-07-11
      • 2021-04-09
      • 2018-11-27
      • 1970-01-01
      相关资源
      最近更新 更多