【问题标题】:Hoare's partition not working correctly (quicksort)Hoare 的分区无法正常工作(快速排序)
【发布时间】:2015-05-15 12:25:14
【问题描述】:

所以在遵循 Cormen 的快速排序和 hoares 分区算法之后,这是我能够生成的代码。该数组部分使用未初始化的元素/垃圾元素排序,我无法终生弄清楚为什么......我认为我完全按照书中所写的那样遵循了算法。

以下是本书的伪代码:

HOARE-PARTITION(A, p, r)
1 x = A[p]
2 i = p - 1
3 j = r + 1
4 while TRUE
5     repeat
6        j = j - 1
7     until A[j] <= x
8     repeat
9        i = i + 1
10    until A[i] >= x
11    if i < j
12        exchange A[i] with A[j]
13    else return j

这是我翻译成的 C++ 代码:

void quickSort(int arr[], int p, int r){
    if(p < r){
        int q = hoare_partition(arr, p, r);
        quickSort(arr, p, q-1);
        quickSort(arr, q+1, r);
    }
}

int hoare_partition(int arr[], int p, int r){
    int x = arr[p];
    int i = p - 1;
    int j = r + 1;
    while(true){
        do{
            j--;
        }while(arr[j] > x);
        do{
            i++;
        }while(arr[i] < x);
        if(i < j){
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        else 
            return j;
    }
}

我用下面的来测试一下

cout << endl << endl << "Testing quicksort" << endl;
int tarr[10] = {2, 30, 1, 99, 46, 33, 48, 67, 23, 76};
quickSort(tarr, 0, 10);
cout << "arr after quicksort: ";
for(int i = 0; i < 10; i++){
    cout <<  tarr[i] << " ";
}
cout << endl;

输出

arr after quicksort: -2146162183 1 2 23 30 33 46 48 67 76

提前感谢任何帮助...谢谢

编辑

将测试用例调用更改为 quickSort(arr, 0, 9) 解决了这种情况。

但是,使用反向排序的数组作为输入,这是输出:

arr2 is:
30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
arr2 after quicksort :
1 3 5 7 9 11 13 15 17 19 20 21 18 22 16 23 14 24 12 25 10 26 8 27 6 28 4 29 2 30

使用此测试代码:

int arr2[30];
fillArrayReverse(arr2, 30);
cout << "arr2 is :" << endl;
for(int i = 0; i < 30; i++){
    cout << arr2[i] << " ";
}
cout << endl;
quickSort(arr2, 0, 29);
cout << "arr2 after quicksort: " << endl;
for(int i = 0; i < 30; i++){
    cout << arr2[i] << " ";
}
cout << endl;

【问题讨论】:

  • 您确实需要注意基于 0 的数组,而不是基于 1 的数组,正如您在对答案的评论中所指出的那样。

标签: c++ algorithm quicksort


【解决方案1】:

书中的伪代码是正确的。问题不在于j 被返回(这是正确的),而在于quickSort 函数本身。它实际上应该如下所示:

void quickSort( int arr[], int p, int r )
{
    if( p < r )
    {
        int q = hoare_partition( arr, p, r );
        quickSort( arr, p, q );
        quickSort( arr, q + 1, r );
    }
}

请注意,我们在第一次调用quickSort 时删除了q - 1,并仅将其替换为q。之前,我们基本上跳过了枢轴点,只对围绕它的项目进行排序。在查看了 wikipedia 上快速排序的 Hoare 分区伪代码后,我注意到了这种差异。

【讨论】:

  • 感谢您发布此内容,另一个答案显然是错误的,因为您应该返回 i 而不是 j。 Hoare 的重点不是将数组拆分为[items smaller than partition] partitioning element [items larger than or equal to partition],而是将数组拆分为[items smaller] [items larger or equal]。正如您所提到的,然后我们对两个子数组进行快速排序 - 但与 Lomuto 分区不同,分区元素尚未位于正确的位置,因此它必须包含在对快速排序的递归调用中。
【解决方案2】:

这是您的测试代码有问题。第三个参数应该是最后一个元素的索引,而不是元素个数:

quickSort(tarr, 0, 9);

您正在读取数组的末尾。

有关 Hoare 分区、快速排序和 Cormen 等的更多信息,请参阅this question

解决您遇到的其他问题的简单方法是将 hoare_partition() 更改为 return i 而不是 j。有关详细信息,请参阅链接(据报道这是书中的错误)。

【讨论】:

  • 书中说“要对整个数组 A 进行排序,初始调用是 QUICKSORT(A, 1, A.length)。”但话又说回来,这本书是通过 1 索引数组进行的。所以这一定是为什么它使用长度而不是长度-1....
  • 它仍然不能在反向排序的数组上工作,用详细信息对我的问题进行了编辑
猜你喜欢
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-06
相关资源
最近更新 更多