【问题标题】:Encountering an infinite loop in quicksort(hoare), but I don't seem to find the issue在快速排序(hoare)中遇到无限循环,但我似乎没有找到问题
【发布时间】:2019-04-25 14:34:43
【问题描述】:

所以,我写了一个快速排序算法和一个 hoare-partition 算法。不知何故,当我尝试在 main() 中运行示例案例时,它挂断了 quickSort(test, 0,3)。似乎有一个无限循环。我不知道如何解决它,因为这两个功能似乎都很好。

我尝试过调试,但我对 c 还很陌生。我注意到 quickSort(test,0,3) 递归调用自己。所以我知道这个问题与高而不是减少有关。但是我从一张大学幻灯片中获取了示例伪代码来构建该功能,并且一切似乎都排成一行。

void printArray(int A[], int high) {
    for (int i=0; i<=high; i++) {
         printf("%d ", A[i]);
    }
}

int partitionHoare(int A[], int low, int high) {
    int pivot=A[low];
    int left = low-1;
    int right= high+1;

    while (1){
        while (1){
            left++;
            if (A[left]>=pivot) break;
        }
        while (1){
            right--;
            if (A[right]<=pivot) break;
        }


        if (left<right)  {
            int temp=A[left];
            A[left]=A[right];
            A[right]=temp;
        }
        else return left;
    }
}

void quicksort(int A[], int low, int high){
    if (low<high){
        int middle=partitionHoare(A,low, high);
        quicksort(A, low,middle-1);
        quicksort(A, middle, high);
    }
}


void main (){
    int test[]={64,81,24,42,90,30,9,95};
    quicksort(test,0,7);
    printArray(test,7);

我实际上希望测试数组按如下排序打印出来: "9、24、30、42、64、81、90、95"

【问题讨论】:

  • 请发minimal reproducible example,以便我们重现问题并帮助您调试。
  • OT: about: void main (){ main() 的返回类型始终为int,从不为void
  • 运行发布的代码(在添加#include &lt;stdio.h&gt;main() 末尾的“}”大括号之后)代码会导致段错误事件,而不是“永远”运行。问题似乎源于:`quicksort(A, middle, high);`
  • 于是我把void main()改成了int main(),没有区别。什么是段错误事件以及如何处理它。正如我所说,我是 c 和一般编程的新手。
  • 问题的根源在于函数:int partitionHoare(int A[], int low, int high) { 建议用一些代表值遍历该函数

标签: c quicksort hoare-logic


【解决方案1】:

您的quicksort() 函数存在逻辑缺陷:

void quicksort(int A[], int low, int high){
    if (low<high){
        int middle=partitionHoare(A,low, high);
        quicksort(A, low,middle-1);
        quicksort(A, middle, high);
    }
}

它不保证递归会终止。

具体来说,如果在某个长度大于 1 的子数组中,第一个元素最少且不重复,则 partitionHoare() 将返回等于 low 的值,而无需修改数组。在这种情况下,对左子数组的递归调用将什么也不做,但对 right 子数组的递归调用将准确地重复当前参数。一切都没有改变,同样的事情肯定会再次发生,一次又一次,无限期地发生。

在这种情况下,您可以通过在quicksort() 中测试是否为middle == low 来打破无限递归,但这并不能为您提供正确的排序。

这里的一个常见解决方案是双重的:

  1. 确保分区函数将枢轴值交换为其报告的枢轴索引。这肯定是该值的正确最终位置。
  2. 递归时,从 both 子数组中排除枢轴索引(我们知道其值是正确的),这样每个子问题肯定小于父问题。

【讨论】:

    【解决方案2】:

    更改分区以返回右(而不是左)。将两个递归调用更改为 |快速排序(A,低,中); |快速排序(A,中间+1,高);。这将与 wiki 文章的示例完全匹配:

    https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme

    您可能想要更改“中间”的名称。 Wiki 示例将其称为 p 表示分区拆分索引(而不是表示到枢轴的索引),因为使用 Hoare 分区方案,枢轴和等于枢轴的元素可能会在左分区的末尾和/或在正确的分区。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多