Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.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_Merge_Segmentation Fault_Mergesort - Fatal编程技术网

C:元素数不均匀的数组的合并排序

C:元素数不均匀的数组的合并排序,c,recursion,merge,segmentation-fault,mergesort,C,Recursion,Merge,Segmentation Fault,Mergesort,我一直在为我的程序编程课做一个作业,在那里我们得到了一个不能完全运行的合并排序程序。它对整数为偶数的数组执行合并排序,但对整数为奇数的数组抛出分段错误 我理解排序是如何工作的,之所以抛出分段错误,是因为奇数导致了分段错误,因为数组不知何故被过度填充。我还知道解决方案将涉及测试原始数组是偶数还是奇数,然后根据这一点将值以不同的方式传递给merge函数。尽管我确实了解这个项目,但为了让它正常工作,我已经努力了好几个星期,希望有人能给我一些建议 在发布这篇文章之前,我已经做了很多关于答案的研究,但是所

我一直在为我的程序编程课做一个作业,在那里我们得到了一个不能完全运行的合并排序程序。它对整数为偶数的数组执行合并排序,但对整数为奇数的数组抛出分段错误

我理解排序是如何工作的,之所以抛出分段错误,是因为奇数导致了分段错误,因为数组不知何故被过度填充。我还知道解决方案将涉及测试原始数组是偶数还是奇数,然后根据这一点将值以不同的方式传递给merge函数。尽管我确实了解这个项目,但为了让它正常工作,我已经努力了好几个星期,希望有人能给我一些建议

在发布这篇文章之前,我已经做了很多关于答案的研究,但是所有其他的例子都涉及到带结构的合并排序程序,这超出了我到目前为止所学的内容。你会在下面我发布的代码中看到。此外,完整的程序还涉及一些其他文件,但我只包括了
mergesort.c
文件和
merge.c
文件,正如我的教授所保证的那样,这些文件是唯一需要进行任何更改的地方。
main
文件工作正常,只负责填充数组和调用
mergesort
函数。如果其他文件是必要的,让我知道,我会张贴他们。我没有这样做的唯一原因是因为我们使用的是Linux shell,我还没有找到一种实用的方法将代码从shell复制并粘贴到我自己的操作系统上,而编写代码需要一段时间

提前感谢您提供的任何建议。这是代码

mergesort.c

#include <"mergesort.h">

void mergesort(int key[], int n) //key is the array, n is the size of key
{
    int j, k, m, *w;

    w = calloc(n, sizeof(int));
    assert(w != NULL);

    for (k = 1; k < n; k *= 2) {
        for (j = 0; j < n - k; j += 2 * k) {
            merge(key + j, key + j + k, w + j, k, k);
        }
        for (j = 0; j < n; ++j) {
            key[j] = w[j];
        }   
    }
    free(w);
}
#include "mergesort.h"

void merge(int a[], int b[], int c[], int m, int n) {
    int i = 0, j = 0, k = 0;

    while (i < m && j < n) {
        if (a[i] < b[j]) {
            c[k++] = a[i++];
        } else {
            c[k++] = b[j++];
        }   
    }

    while (i < m) {
        c[k++] = a[i++];
    }
    while (j < n) {
        c[k++] = b[j++];
    }   
}
#包括
void mergesort(int key[],int n)//key是数组,n是key的大小
{
int j,k,m,*w;
w=calloc(n,sizeof(int));
断言(w!=NULL);
对于(k=1;k
merge.c

#include <"mergesort.h">

void mergesort(int key[], int n) //key is the array, n is the size of key
{
    int j, k, m, *w;

    w = calloc(n, sizeof(int));
    assert(w != NULL);

    for (k = 1; k < n; k *= 2) {
        for (j = 0; j < n - k; j += 2 * k) {
            merge(key + j, key + j + k, w + j, k, k);
        }
        for (j = 0; j < n; ++j) {
            key[j] = w[j];
        }   
    }
    free(w);
}
#include "mergesort.h"

void merge(int a[], int b[], int c[], int m, int n) {
    int i = 0, j = 0, k = 0;

    while (i < m && j < n) {
        if (a[i] < b[j]) {
            c[k++] = a[i++];
        } else {
            c[k++] = b[j++];
        }   
    }

    while (i < m) {
        c[k++] = a[i++];
    }
    while (j < n) {
        c[k++] = b[j++];
    }   
}
#包括“mergesort.h”
无效合并(整数a[],整数b[],整数c[],整数m,整数n){
int i=0,j=0,k=0;
而(i
您的代码有一些问题:

  • include预处理器指令不正确,请使用
    #include“mergesort.h”
    #include

  • 您必须正确计算传递给
    merge()
    的数组的大小,这样它的读取就不会超过最后一个块的末尾。按照当前编码,
    n
    必须是
    2
    的幂才能避免未定义的行为

以下是
mergesort.c
的更正版本,供您参考:

#include "mergesort.h"

void mergesort(int key[], int n) {
    // key is the array, n is the number of elements
    int i, j, k, m;
    int *w;

    // allocate the working array
    w = calloc(n, sizeof(int));
    // abort the program on allocation failure
    assert(w != NULL);

    // for pairs of chunks of increasing sizes
    for (k = 1; k < n; k *= 2) {
        // as long as there are enough elements for a pair
        for (j = 0; j + k < n; j = j + k + m) {
            // compute the size of the second chunk: default to k
            m = k;
            if (j + k + m > n) {
                // chunk is the last one, size may be smaller than k
                m = n - j - k;
            }
            // merge adjacent chunks into the working array
            merge(key + j, key + j + k, w + j, k, m);
            // copy the resulting sorted list back to the key array
            for (i = 0; i < k + m; i++) {
                key[j + i] = w[j + i];
            }
        }
    }
    free(w);
}
您可以通过删除函数
merge()
中索引变量的近一半测试来进一步改进实现:

静态无效合并(int a[],size\t m,int b[],size\t n,int c[]){
/*总是在m>0和n>0时调用*/
对于(尺寸i=0,j=0,k=0;){
if(a[i]
您可以使用以下进一步的想法改进
mergesort
merge

  • 通过比较
    merge
    a
    的最后一个元素和
    b
    的第一个元素,可以在部分或完全排序的数组上大大提高速度

  • merge
    可以返回要复制回的元素数,从而删除已排序案例中的所有复制

  • 通过将左侧块复制到临时数组并合并到
    数组中,可以减小临时数组的大小

  • 合并平衡块大小而不是2次幂可以减少非2次幂数组大小的比较总数,但使用递归方法更容易实现


所以我找到了分段错误的来源。如果仔细查看mergesort中的第一个内部for循环:

        for(j = 0; j < n - k; j += 2 * k)
        {
            merge(key + j, key + j + k, w + j, k, k);
        }  
现在我们排除了分割错误,我们可以进入第二部分:使其适用于所有尺寸。之所以它只适用于2的幂次大小(甚至不是所有的偶数大小:尝试排序[2,3,5,6,4,1],你会看到),是因为你的
k
。正是
k
设置了用于确定将在循环中合并的切片的大小
k
在每一轮之后都会乘以2,因此它只会得到2的幂次方的大小!当它不是2的幂时,它会忽略“超过”2幂的部分…如果你明白我的意思?在我们做出解决分段错误的更改之前,它会尝试这样做,但由于这个原因失败(并返回一个错误)。 我们现在要做的是把它整理成他忽略的最后一片。我将只复制mergesort函数,因为它是唯一会更改的:

void mergesort(int key[], int n) //key is the array, n is the size of key
{
    int j, k, neglected, *w;
    w = calloc(n, sizeof(int));
    assert(w != NULL);

    for(k = 1; k < n; k *= 2){
        for(j = 0; j <= n - (k*2); j += 2 * k){
            merge(key + j, key + j + k, w + j, k, k);
        }

        //size of part that got neglected (if it could fully be divided in slices of 2*k, this will be 0)
        neglected = n % (2*k);

        //copy everything except the neglected part (if there was none, it will copy everything)
        for(j = 0; j < n-neglected; ++j) {
            key[j] = w[j];
        }

        if(neglected != 0 && neglected < n){ //couldn't devide it fully in slices of 2*k ==> the last elements were left out! merge them together with the last merged slice 
            merge(key + n - (2*k) - neglected, key + n-neglected, w + n - (2*k) - neglected, 2*k, neglected);
            for(j = n - (2*k) - neglected; j < n; ++j) { //copy the part we just merged
                key[j] = w[j];
            }
        }

        for(j = 0; j < n; ++j) {
            key[j] = w[j];
        }
    }
    free(w);
}
void mergesort(int key[],int n)//key是数组,n是key的大小
{
int j,k,忽略,*w;
w=calloc(n,sizeof(int));
断言(w!=NULL);
对于(k=1;kvoid mergesort(int key[], int n) //key is the array, n is the size of key
{
    int j, k, neglected, *w;
    w = calloc(n, sizeof(int));
    assert(w != NULL);

    for(k = 1; k < n; k *= 2){
        for(j = 0; j <= n - (k*2); j += 2 * k){
            merge(key + j, key + j + k, w + j, k, k);
        }

        //size of part that got neglected (if it could fully be divided in slices of 2*k, this will be 0)
        neglected = n % (2*k);

        //copy everything except the neglected part (if there was none, it will copy everything)
        for(j = 0; j < n-neglected; ++j) {
            key[j] = w[j];
        }

        if(neglected != 0 && neglected < n){ //couldn't devide it fully in slices of 2*k ==> the last elements were left out! merge them together with the last merged slice 
            merge(key + n - (2*k) - neglected, key + n-neglected, w + n - (2*k) - neglected, 2*k, neglected);
            for(j = n - (2*k) - neglected; j < n; ++j) { //copy the part we just merged
                key[j] = w[j];
            }
        }

        for(j = 0; j < n; ++j) {
            key[j] = w[j];
        }
    }
    free(w);
}