用递归实现C语言中的合并排序

用递归实现C语言中的合并排序,c,sorting,recursion,mergesort,C,Sorting,Recursion,Mergesort,这是我用C语言编写的合并排序代码。我不明白这里有什么问题。我对指针的了解不多。merge函数接收2个数组并合并它们。sort函数是一个递归函数,用于对数组进行排序 int * merge(int *fir, int n, int *sec, int m){ int res[m+n]; int x=0, y=0; for(int i = 0; i < m+n; i++){ if(*(fir+x)<=*(sec+y)){

这是我用C语言编写的合并排序代码。我不明白这里有什么问题。我对指针的了解不多。merge函数接收2个数组并合并它们。sort函数是一个递归函数,用于对数组进行排序


int * merge(int *fir, int n, int *sec, int m){
    int res[m+n];
    int x=0, y=0;
    for(int i = 0; i < m+n; i++){
        if(*(fir+x)<=*(sec+y)){
            res[i] = *(fir+x);
            x++;
        }else{
            res[i] = *(sec+y);
            y++;
        }

    }
    return res;
}

int * sort(int A[], int n){
    if(n == 1){
        return A;
    }
    int mid = n/2;
    int AL[mid], AR[n-mid];
    for(int i = 0; i < mid; i++){
        AL[i] = A[i];
    }
    for(int i = 0; i < n-mid; i++){
        AR[i] = A[i+mid];
    }
    int *BL, *BR;
    BL = sort(AL, mid);
    BR = sort(AR, n-mid);
    return(merge(BL, mid, BR, n-mid));
}

int main(){
    int n;
    scanf("%d", &n);
    int A[n];
    for(int i = 0; i < n; i++){
        scanf("%d", &A[i]);
    }
    int *sortedArray;
    sortedArray = sort(A, n);
    for(int i = 0; i < n; i++){
        printf("%d ", *(sortedArray+i));
    }

    return 0;
}

这里有两个问题:首先,您将部分数组合并到一个临时本地数组中,在您从
merge
返回后,该数组将超出范围。返回的指针指向invlid内存。这就是警告的内容

其次,在合并时,您不检查您的读取是否超出了部分数组的限制:当您访问
fir
时,条件
x
必须为真,同样对于
y
sec

返回指向已排序或合并数组的第一个元素的指针也会造成混乱。这建议您创建新的排序和合并数组(这就是您在
merge
中尝试执行的操作)。这对于垃圾收集的morern语言来说是可以的,但是C不是这样工作的

在C语言中,如果您需要新的内存,您必须分配它,然后显式地释放它。在像您这样的递归函数中,这很乏味,因为您只关心最终排序的数组,而不关心中间结果。因此,C排序算法通常“就地”工作:在排序和元素交换时使用相同的内存。元素的原始顺序将丢失,除非在排序之前复制

对于合并排序,您需要辅助内存。在本例中,您使用临时数组
AL
AR
,它们是原始数组
A
内容的副本。现在,当您合并时,您可以将
AL
AR
合并回
A

因此,在创建临时本地数组之前,传入
a
,以便可以用已排序的元素填充该数组:

void sort(int A[], int n)
{
    if (n > 1) {
        int mid = n / 2;
        int AL[mid], AR[n - mid];

        for (int i = 0; i < mid; i++) AL[i] = A[i];
        for (int i = 0; i < n - mid; i++) AR[i] = A[i + mid];
        
        sort(AL, mid);
        sort(AR, n - mid);
        
        merge(A, AL, mid, AR, n - mid);
    }
}

您正在读取超出数组边界的内容。合并阵列时,有四种情况。您的代码忽略了两种情况:一个数组耗尽,而您从另一个数组中获取第一项。此外,还存在返回本地数组地址的问题<代码>分辨率
。从
merge
返回后,该数组将不再有效,指向该数组的指针将为“stale”。(这就是警告的内容。)对于
*(fir+x)
你可以只写
fir[x]
,这样更容易阅读。是的,我理解我的两个错误。非常感谢您指出这些问题!对我明白我做错了什么。非常感谢你帮了我的忙!
void sort(int A[], int n)
{
    if (n > 1) {
        int mid = n / 2;
        int AL[mid], AR[n - mid];

        for (int i = 0; i < mid; i++) AL[i] = A[i];
        for (int i = 0; i < n - mid; i++) AR[i] = A[i + mid];
        
        sort(AL, mid);
        sort(AR, n - mid);
        
        merge(A, AL, mid, AR, n - mid);
    }
}
void merge(int *res, const int *fir, int n, const int *sec, int m)
{
    int x = 0, y = 0;

    for(int i = 0; i < m + n; i++) {
        if      (x == n)            res[i] = sec[y++];
        else if (y == m)            res[i] = fir[x++];
        else if (fir[x] <= sec[y])  res[i] = fir[x++];
        else                        res[i] = sec[y++];
    }
}