Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么我的快速排序会在大型反向排序数组中崩溃?_C_Recursion_Quicksort - Fatal编程技术网

C 为什么我的快速排序会在大型反向排序数组中崩溃?

C 为什么我的快速排序会在大型反向排序数组中崩溃?,c,recursion,quicksort,C,Recursion,Quicksort,我正在学习C语言,并尝试了一种递归快速排序算法。在较小的输入大小下,它可以按预期工作;对于随机生成的阵列,它在所有测试尺寸(高达100000)上都没有问题。使用降序数组时,它会以某种方式在特定数组大小(32506)下中断(Windows给我一条消息,程序已停止工作)。我的代码中是否有任何错误(例如错误的内存分配-我不确定是否正确),或者C在递归调用或其他方面是否有限制 编辑: 我知道我的快速排序实现相当幼稚,而且它在这种输入下表现得非常糟糕,但我没想到它会崩溃 我在Windows10的命令提示符

我正在学习C语言,并尝试了一种递归快速排序算法。在较小的输入大小下,它可以按预期工作;对于随机生成的阵列,它在所有测试尺寸(高达100000)上都没有问题。使用降序数组时,它会以某种方式在特定数组大小(32506)下中断(Windows给我一条消息,程序已停止工作)。我的代码中是否有任何错误(例如错误的内存分配-我不确定是否正确),或者C在递归调用或其他方面是否有限制

编辑: 我知道我的快速排序实现相当幼稚,而且它在这种输入下表现得非常糟糕,但我没想到它会崩溃

我在Windows10的命令提示符下使用GCC和MinGW。我不知道如何确切地找出发生了什么,因为尽管Windows告诉我我的程序已经停止工作,但我并没有收到任何指定的错误消息

#include <stdio.h>
#include <stdlib.h>

int partition(int *a, int lo, int hi) {
    int i = lo; int j = hi+1; int v,t;
    v = a[lo]; //partition element
    while (1) {
        while (a[++i] < v) {if (i == hi) break;}
        while (v < a[--j]) {if (j == lo) break;}
        if (i >= j) break;
        t = a[j]; a[j] = a[i]; a[i]= t; //swap
    }
    t = a[lo]; a[lo] = a[j]; a[j]= t;//swap
    return j;
}

void quicksort(int a[], int lo, int hi) {
    int j;
    if (hi <= lo) return;
    j = partition(a, lo, hi);
    quicksort(a, lo, j-1);
    quicksort(a, j+1, hi);
}

int main()  {
    int len;
    for (len = 32000;len < 40000;len+=100) {
        printf("New Arr with len = %d\n",len);
        int *arr;
        arr = (int*) calloc(len,sizeof(int));
        int j;
        //create descending Array
        for (j = 0; j < len; ++j) {
            arr[j] = len-j;
        }
        printf("start sorting\n");
        quicksort(arr,0,len-1);
        free(arr);
    }
}
#包括
#包括
int分区(int*a、int-lo、int-hi){
int i=lo;int j=hi+1;int v,t;
v=a[lo];//分区元素
而(1){
而(a[++i]=j)断裂;
t=a[j];a[j]=a[i];a[i]=t;//交换
}
t=a[lo];a[lo]=a[j];a[j]=t;//交换
返回j;
}
无效快速排序(int a[],int lo,int hi){
int j;

if(hi递归太深,无法存储在堆栈上。 它必须为每个级别存储
int j=partition(..)
。 有一些声明性技术可以最小化递归堆栈的使用。
例如,将结果作为参数进行处理。但这种情况远比我给出的示例复杂。

对我来说,您的代码在更大的大小(约370000个元素)时失败。您可能会遇到平台限制(可能由于堆栈溢出而限制递归深度).如果没有确切的错误信息,当然很难确定

您的输入集很可能是您的实现的病态案例-请参阅

您可以通过更好地选择轴来减少递归深度-一种常见的技术是取第一个、中心和最后一个元素的中间值。类似于:

int v0 = a[lo], v1 = a[(lo+hi+1)/2], v2 = a[hi];
/* pivot: median of v0,v1,v2 */
int v = v0 < v1 ? v1 < v2 ? v1 : v0 < v2 ? v2 : v0 : v0 < v2 ? v0 : v1 < v2 ? v2 : v1;

完整列表 以下是我最终得到的代码:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int partition(int *a, int i, int j) {
    int v0 = a[i], v1 = a[(i+j+1)/2], v2 = a[j];
    /* pivot: median of v0,v1,v2 */
    int v = v0 < v1 ? v1 < v2 ? v1 : v0 < v2 ? v2 : v0 : v0 < v2 ? v0 : v1 < v2 ? v2 : v1;
    while (i < j) {
        while (a[i] < v && ++i < j)
            ;
        while (v < a[j] && i < --j)
            ;
        int t = a[j]; a[j] = a[i]; a[i]= t; //swap
    }
    /* i == j; that's where the pivot belongs */
    a[i] = v;
    return j;
}

void quicksort(int a[], int lo, int hi) {
    while (lo < hi) {
        int j = partition(a, lo, hi);
        if (j - lo < hi -j) {
            quicksort(a, lo, j-1);
            lo = j+1;
        } else {
            quicksort(a, j+1, hi);
            hi = j-1;
        }
    }
}

int main()  {
    int len = INT_MAX/2+1;
    printf("New Arr with len = %d\n",len);
    int *arr = malloc(len * sizeof *arr);
    if (!arr) return fprintf(stderr, "allocation failed\n"), EXIT_FAILURE;

    /* populate pessimal array */
    for (int j = 0; j < len; ++j) {
        arr[j] = len-j;
    }

    printf("start sorting\n");
    quicksort(arr, 0, len-1);

    /* test - is it sorted? */
    for (int i = 0;  i+1 < len;  ++i)
        if (arr[i] >= arr[i+1])
            return fprintf(stderr, "not sorted\n"), EXIT_FAILURE;
    free(arr);
}
#包括
#包括
#包括
int分区(int*a,int i,int j){
int v0=a[i],v1=a[(i+j+1)/2],v2=a[j];
/*枢轴:v0、v1、v2的中值*/
intv=v0=arr[i+1])
返回fprintf(stderr,“未排序”),退出\u失败;
免费(arr);
}

您使用的编译器是什么?错误是否提到程序停止时堆栈溢出?只是问一下,因为递归程序的一个典型问题是堆栈溢出。
calloc
可能会失败。这可能有助于降序数组是“升序”的最坏输入使用第一个元素轴进行快速排序;它具有二次复杂性,并且很可能递归太深。您需要不同的轴选择方法。如果@molbdnilo确实正确地认为递归深度是问题所在(这很有可能),那么改变轴心选择的另一种选择是切换到半递归算法。也就是说,不是递归地对两个子分区进行排序,而是递归地对较小的子分区进行排序,但只是循环回对较大的子分区进行排序。在不利的情况下,这仍然会有二次运行时间,但它会有对数递归深度我认为,问题在于递归深度(这可以解释为什么它不会在您的系统上与我的系统相同的点崩溃),因为只有您实现了quicksort()函数,它才不会崩溃(测试大小为200000)
int *arr = malloc(len * sizeof *arr);
if (!arr) return fprintf(stderr, "allocation failed\n"), EXIT_FAILURE;
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int partition(int *a, int i, int j) {
    int v0 = a[i], v1 = a[(i+j+1)/2], v2 = a[j];
    /* pivot: median of v0,v1,v2 */
    int v = v0 < v1 ? v1 < v2 ? v1 : v0 < v2 ? v2 : v0 : v0 < v2 ? v0 : v1 < v2 ? v2 : v1;
    while (i < j) {
        while (a[i] < v && ++i < j)
            ;
        while (v < a[j] && i < --j)
            ;
        int t = a[j]; a[j] = a[i]; a[i]= t; //swap
    }
    /* i == j; that's where the pivot belongs */
    a[i] = v;
    return j;
}

void quicksort(int a[], int lo, int hi) {
    while (lo < hi) {
        int j = partition(a, lo, hi);
        if (j - lo < hi -j) {
            quicksort(a, lo, j-1);
            lo = j+1;
        } else {
            quicksort(a, j+1, hi);
            hi = j-1;
        }
    }
}

int main()  {
    int len = INT_MAX/2+1;
    printf("New Arr with len = %d\n",len);
    int *arr = malloc(len * sizeof *arr);
    if (!arr) return fprintf(stderr, "allocation failed\n"), EXIT_FAILURE;

    /* populate pessimal array */
    for (int j = 0; j < len; ++j) {
        arr[j] = len-j;
    }

    printf("start sorting\n");
    quicksort(arr, 0, len-1);

    /* test - is it sorted? */
    for (int i = 0;  i+1 < len;  ++i)
        if (arr[i] >= arr[i+1])
            return fprintf(stderr, "not sorted\n"), EXIT_FAILURE;
    free(arr);
}