C语言 合并排序的实作问题

f0brbegy  于 2022-12-02  发布在  其他
关注(0)|答案(2)|浏览(156)

我不明白我的代码中的问题。我得到我的算法的书是:算法简介,第三版
我知道算法是如何工作的,但是在编码的时候,我的程序只对前4个数字排序。

代码

#include <stdio.h>

void sortArr(int *nums, int arrSize) {
    // nums[start...end]
    // nums[start...mid]  n1
    // nums[mid+1...end]  n2
    int start, mid, end;
    start = 0;
    end = arrSize-1;
    mid = (end + start) / 2;
    int n1, n2;
    n1 = mid - start + 1;
    n2 = end - mid;
    int l[n1], r[n2];
    for (int i = 0; i < n1; i++) {
        l[i] = nums[start + i];
    }

    for (int i = 0; i < n2; i++) {
        r[i] = nums[mid + 1 + i];
    }

    int i, j;
    i = 0;
    j = 0;
    for (int k = start; k < arrSize; k++) {
        if (l[i] <= r[j]) {
            nums[k] = l[i];
            i++;
        } else {
            nums[k] = r[j];
            j++;
        }
    }
}

int main() {
    int arr[] = {3, 41, 52, 26, 38, 57, 9, 49};
    int arrsize = sizeof(arr) / sizeof(arr[0]);
    printf("before sorting: \n");
    for (int i = 0; i < arrsize; i++) {
        printf("%d ", arr[i]);
    }

    sortArr(arr, arrsize);
    printf("\n after sorting: \n");
    for (int i = 0; i < arrsize; i++) {
        printf("%d ", arr[i]);
    }

    return 0;
}
xn1cxnb4

xn1cxnb41#

你的代码有很多问题,包括你只实现了书中的MERGE(MERGESORT的一个子例程),书中使用了一个技巧,即在数组的“两半”后附加+infinity,以避免在合并时出现处理其中一半用完的代码。通过将INT_MAX追加到L和R并要求原始数组不包含该值),但您没有用任何内容替换它,因此您的代码在合并时很容易读取边界之外的内容。
这是一个基于书本算法的工作版本。与问题中的代码相比,它还避免了VLA(可变长度数组),VLA在使用一次性malloc-ed缓冲区的大型输入数组上可能会失败,并使用更正确的size_t作为数组索引。
在合并时,代码在if语句中为liri添加了一些额外的测试,这与本书的+infinity技巧不同,在C中运行得更好。
顶级函数MERGESORT如果成功返回1,如果不成功返回0(如果malloc失败,就会发生这种情况)。Assert用于检查关于各种索引和大小的假设--只有在代码中存在bug时才会失败,并且可以编译出来。
它运行在一个可配置大小的随机数组上(当前为1234),并在末尾打印出okfailed,这取决于数组是否实际排序。(注意:rand通常是要避免的,因为它通常是一个随机数的供应不足,但在这里它是好的)。
请注意,这段代码是精心编写的,但它仍然没有得到很好的测试,所以你可能会发现错误!

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

void MERGE(int *nums, int *buffer, size_t start, size_t mid, size_t end) {
    size_t n1 = mid - start + 1;
    size_t n2 = end - mid;
    assert(n1 > 0);
    assert(n2 > 0);
    memcpy(buffer, nums + start, (end - start + 1) * sizeof(int));
    int *L = buffer;
    int *R = buffer + n1;
    size_t li = 0, ri = 0;
    for (size_t i = start; i <= end; i++ ){
        if (li < n1 && (ri == n2 || L[li] <= R[ri])) {
            assert(li < n1);
            nums[i] = L[li++];
        } else {
            assert(ri < n2);
            nums[i] = R[ri++];
        }
    }
}

void MERGESORT0(int *nums, int *buffer, size_t start, size_t end) {
    if (end == start) return;
    size_t mid = start + (end - start) / 2;
    MERGESORT0(nums, buffer, start, mid);
    MERGESORT0(nums, buffer, mid+1, end);
    MERGE(nums, buffer, start, mid, end);
}

int MERGESORT(int *nums, size_t size) {
    if (size == 0) {
        return 1;
    }
    int *buffer = malloc(sizeof(int) * size);
    if (!buffer) return 0;
    MERGESORT0(nums, buffer, 0, size-1);
    free(buffer);
    return 1;
}

#define N 1234
int main(){
    int arr[N];
    for (size_t i = 0; i < N; i++) {
        arr[i] = rand();
    }
    size_t arrsize = sizeof(arr)/sizeof(arr[0]);
    printf("before sorting: \n");
    for(size_t i=0; i<arrsize; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
    if (!MERGESORT(arr, arrsize)) {
        printf("failed\n");
        exit(1);
    }
    printf("after sorting: \n");
    int failed = 0;
    for(size_t i=0; i<arrsize; i++){
        if (i > 0 && arr[i] < arr[i-1]) failed = 1;
        printf("%d ", arr[i]);
    }
    printf("\n");
    printf("%s\n", failed ? "failed" : "ok");
    return 0;
}
k5ifujac

k5ifujac2#

将此print命令添加到最后一个循环:printf("%d %d %d\n", k, i, j);
n1 = n2 = 4,所以两个数组的值都只到索引3为止。但在最后一个循环中,您从0到6运行i。这是行不通的。
您可以添加更多的打印命令,使用纸和笔运行算法,并希望找到出错的地方。

相关问题