【问题标题】:why does my program on mergesort trigger a segmentation fault? [closed]为什么我的合并排序程序会触发分段错误? [关闭]
【发布时间】:2015-03-14 12:43:12
【问题描述】:
#include<stdio.h>
void merge(int a[],int left[],int l,int right[],int r){
int i=0,j=0,k=0;
while(i<l&&j<r){
    if(left[i]<=right[j]){
        a[k]=left[i];
        k++;
        i++;
    }
    else{
        a[k]=right[j];
        k++;
        j++;
    }
}
while(i<l){
    a[k]=left[i];
    k++;
    i++;
   }
while(j<r){
    a[k]=right[j];
    k++;
    j++;
  }
}
void mergesort(int a[],int s,int n){
int i;
int mid=(s+n)/2;
int left[mid],right[n-mid];

if(n<2) return;

else{

    for(i=s;i<mid;i++){
        left[i]=a[i];
    }
    for(i=mid;i<n;i++){
        right[i]=a[i];
    }
    mergesort(left,s,mid);
    mergesort(right,n-mid,n);
    merge(a,left,mid,right,n-mid);
   }
 }
int main(int argv,char*argc){
int a[]={9,8,7,5,1,2,4,3,6},i;
printf("sorting....");
mergesort(a,0,9);
for(i=0;i<10;i++){
    printf("\n");
    printf("%d",a[i]);
}
return 1;
}

程序在给出输出之前终止...请帮助.. 逻辑取自mycodeschool.org

【问题讨论】:

  • 乍一看,您的mergesort 接受大于2 的n 值,只要n 保持大于2,它就会继续执行。但是您递归调用@ 987654326@ 具有相同的n 值,因此您将获得无限递归。
  • 那么先生,我该怎么办?
  • 尝试修复你的代码逻辑。你为什么用相同的值调用mergesort
  • 同值先生是什么意思?
  • 不用叫我先生 :),我的意思是,看mergesort(right,n-mid,n);.. 你的第三个参数在递归调用中没有改变(导致无限递归)。您要么递归调用了错误的函数,要么 if(n&lt;2) return; 不足以停止递归。

标签: c algorithm sorting data-structures


【解决方案1】:

如 cmets 中所写,for(i=mid+1;i&lt;n;i++){ right[i]=a[i]; } 上升到 i=n-1,但 right 被声明为 int mid=(s+n)/2; int left[mid],right[n-mid];right 太小,它会触发未定义的行为,例如分段错误和过早终止。

为了克服这个问题,引入了另一个索引jint j=0;for(i=mid+1;i&lt;n;i++){ right[j]=a[i]; j++; },数组left也是如此。对mergesort() 的调用必须相应更改:

        mergesort(left,mid);
        mergesort(right,n-mid);

第二个参数s 已被删除。它可以稍后重新引入,以避免不必要的副本并减少内存占用。

额外的小问题是int a[]={9,8,7,5,1,2,4,3,6},i;...for(i=0;i&lt;10;i++)a 有 9 个项目,for 循环尝试访问第十个项目 a[9]

这是一个提供预期输出的更正代码。用gcc main.c -o main编译它

#include<stdio.h>
void merge(int a[],int left[],int l,int right[],int r){
    int i=0,j=0,k=0;
    while(i<l&&j<r){
        if(left[i]<=right[j]){
            a[k]=left[i];
            k++;
            i++;
        }
        else{
            a[k]=right[j];
            k++;
            j++;
        }
    }
    while(i<l){
        a[k]=left[i];
        k++;
        i++;
    }
    while(j<r){
        a[k]=right[j];
        k++;
        j++;
    }
}
void mergesort(int a[],int n){
    int i;
    int mid=(n)/2;
    int left[mid],right[n-mid];

    if(n<2) return;

    else{
        int j=0;
        for(i=0;i<mid;i++){
            left[j]=a[i];
            j++;
        }
        j=0;
        for(i=mid;i<n;i++){
            right[j]=a[i];
            j++;
        }
        mergesort(left,mid);
        mergesort(right,n-mid);
        merge(a,left,mid,right,n-mid);
    }
}
int main(int argv,char*argc){
    int a[]={9,8,7,5,1,2,4,3,6},i;
    printf("sorting....\n");
    mergesort(a,9);
    for(i=0;i<9;i++){

        printf("%d\n",a[i]);
    }
    return 0;
}

【讨论】:

  • 请注意,mergesort 方法的此实现使用n*log2(n) 时间来完成,这没关系,但也有n* log2(n)*sizeof int 字节的堆栈空间!潜在的大量内存,可能超过可用的堆栈空间。此外,不可能优雅地检测到这种堆栈溢出。我建议使用分配有malloc 的单个临时数组,以及更有效的排序算法,例如基数排序,适合您的问题,并且对于n 的中到大值更快。
  • @chqrlie :这个实现显然是有限的......它只是解决了提问者的问题,但它不能处理大数组。在这种情况下,最好的方法是使用qsort
猜你喜欢
  • 2021-01-11
  • 2021-03-30
  • 1970-01-01
  • 2018-10-18
  • 2017-10-14
  • 2021-12-09
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
相关资源
最近更新 更多