当前位置: 首页 > 知识库问答 >
问题:

C中的递归mergesort不修改原始数组

冀子石
2023-03-14

我正在C中实现合并排序。我有一个合并函数-merge(int array[],int start,int middle,int end)和一个mergeSort函数-mergeSort(int*array,unsigned int size)

如果对原始数组的前半部分和后半部分进行排序(例如:5,6,7,8,1,2,3,4),则合并排序可以很好地工作。这是因为我的merge函数无论在什么情况下都要传递原始数组,并且当它被赋予2个排序数组时(正如预期的那样),它可以工作。我的问题是他们什么时候不是。每次调用merge时,我的原始数组都没有被修改,尽管我已经对它进行了编程。有人能知道我的问题在哪里吗?代码在下面。

当我在输入{10,9,8,7,6,5,4,3,2,1}上运行此代码时,它将返回{5,4,3,2,1,0,10,9,8,7,6}

void merge(int arr[], int l, int m, int r) {

    int size1 = m - l + 1;
    int size2 = r - m;

    int arr1[size1];
    int arr2[size2];

    int i;

    for ( i = 0; i < size1; i++ ) {
        arr1[i] = arr[l + i];
    }

    for ( i = 0; i < size2; i++ ) {
        arr2[i] = arr[m + i + 1];
    }

    i = 0;
    int j = 0;
    int k = 0;

    while ( i < size1 && j < size2 ) {
        if ( arr1[i] < arr2[j] ) {
            arr[k] = arr1[i];
            i++;
            k++;
        } else {
            arr[k] = arr2[j];
            j++;
            k++;
        }
    }
    while ( i < size1 ) {
        arr[k] = arr1[i];
        i++;
        k++;
    }
    while ( j < size2 ) {
        arr[k] = arr2[j];
        j++;
        k++;
    }
}

void mergeSort(int *array, unsigned int size) {
    int start = 0;
    int middle = (size / 2) - 1;
    int end = size - 1;

    if ( size < 2 ) {
        return;
    }

    int m = ( size / 2 );

    int arr1[m];
    int arr2[size - m];

    int i;

    for ( i = 0; i < middle + 1; i++ ) {
        arr1[i] = array[i];
        printf("%d\n", arr1[i]);
    }

    for ( i = middle + 1; i < size; i++ ) {
        arr2[i - (middle + 1)] = array[i];
    }

    mergeSort(arr1, m);
    mergeSort(arr2, size - m);
    merge(array, start, middle, end);
}

共有2个答案

黎征
2023-03-14

您的代码中存在多个问题:

  • mergeSort函数将数组拆分为2个局部数组,并递归调用自身对它们进行排序,但merge阶段不将这些排序的数组作为输入。您应该直接使用参数数组的部分内容。
  • 大小计算非常繁琐,许多调整会对size的小值造成问题。使用一个简单的约定:传递end作为第一个元素经过数组结尾的偏移量。这样计算大小只需从end减去start
  • merge函数将k初始化为0而不是l

以下是一个修正版本:

void merge(int arr[], int start, int m, int end) {
    int size1 = m - start;
    int size2 = end - m;
    int arr1[size1];
    int arr2[size2];
    int i, j, k;

    for (i = 0; i < size1; i++) {
        arr1[i] = arr[start + i];
    }
    for (i = 0; i < size2; i++) {
        arr2[i] = arr[m + i];
    }

    i = j = 0;
    k = start;

    while (i < size1 && j < size2) {
        if (arr1[i] < arr2[j]) {
            arr[k++] = arr1[i++];
        } else {
            arr[k++] = arr2[j++];
        }
    }
    while (i < size1) {
        arr[k++] = arr1[i++];
    }
    while (j < size2) {
        arr[k++] = arr2[j++];
    }
}

void mergeSort(int *array, unsigned int size) {
    if (size >= 2) {
        int m = size / 2;
        mergeSort(array, m);
        mergeSort(array + m, size - m);
        merge(array, 0, m, size);
}

Bob__建议进行简化,只将数组的前半部分保存到ARR1中,而不需要ARR2。这里是一个修改版本,还删除了start(始终为0)和其他一些简化:

void merge(int arr[], size_t m, size_t size) {
    int arr1[m];
    size_t i, j, k;

    for (i = j = k = 0; j < m; j++) {
        arr1[j] = arr[j];
    }

    while (i < m && j < size) {
        if (arr1[i] < arr[j]) {
            arr[k++] = arr1[i++];
        } else {
            arr[k++] = arr[j++];
        }
    }
    while (i < m) {
        arr[k++] = arr1[i++];
    }
}

void mergeSort(int *array, size_t size) {
    if (size >= 2) {
        size_t m = size / 2;
        mergeSort(array, m);
        mergeSort(array + m, size - m);
        merge(array, m, size);
}

但是请注意,为arr1分配自动存储(也就是堆栈上的存储)可能会导致大型数组(通常大于几十万个元素)的未定义行为。从堆中分配临时数组可以避免这个问题,但代价是额外的开销和分配失败的可能性。

顾宸
2023-03-14

mergeSort中,在执行mergeSort(arr1,m)mergeSort(arr2,size-M)之后,实际上并没有对arr1arr2执行任何操作。

对于一个简单的修复,我建议不要使用变量ARR1ARR2,而是直接对array的部分调用mergeSort,如下所示:

void mergeSort(int* array, unsigned int size) {
    int start = 0;
    int middle = (size / 2);
    int end = size - 1;

    if ( size < 2 ) {
        return;
    }

    mergeSort(array, middle);
    mergeSort(array + middle, size - middle);
    merge(array, start, middle - 1, end);
}
 类似资料:
  • 我有一个递归函数,需要创建一个由特殊对象组成的数组... 我的自定义对象由此类填充: 这是我的递归函数: 在这个函数中,RandomBool()方法随机返回true/false。。。RandomId()也不重要。。。 问题在于“位置”数组。我希望每个项目都有特定的位置数组,例如: 对于第一步,每个项目都需要有:[0]、[1]、[2]、[3]。。。 下一步,假设我们选择了3:[3,0],[3,1],

  • 问题内容: 我正在使用一个用于保存和调用屏幕状态的系统,这是我第一次弄这种东西,所以我不确定如何解决此问题的最佳方法是什么,但是我目前存储了所有“ PreviewMonitor”数组列表中的对象(大约40个左右)。问题是,当我创建要存储的名为“ allPreviewMonitors”的ArrayList的副本时,最终得到的ArrayList的元素随着原始元素的更新而不断变化。实际上,好像我正在使用

  • 问题内容: 我有以下字典: 我想将一个条目附加到key1-> key2-> key3上,其值为’blah’,产生: 我正在寻找一种与键的数量无关的通用解决方案,即即使不存在从key3向下的键,key1-> key2-> key3-> key4-> key5也应该起作用。这样我得到: 提前致谢。 问题答案: 您可以使用该函数遍历一系列嵌套字典: 演示: 当密钥不存在时,此版本引发异常: 但您可以替换

  • 本文向大家介绍在JavaScript中使用递归求和数组的修改后的版本,包括了在JavaScript中使用递归求和数组的修改后的版本的使用技巧和注意事项,需要的朋友参考一下 假设,我们需要编写一个递归函数,该求和函数将Numbers数组的所有元素相加,但有一个转折,而转折是我们编写的递归函数不能初始化任何额外的变量(内存)。 就像我们不能使用变量来存储总和或保持数组索引的计数一样,所有这些都必须使用

  • 假设数组A:1,2,3,1,1,3。不同的整数应在数组B中:1,2,3。然后,函数应打印:[1,1][1,2][1,3][2,1][2,2][2,3][3,1][3,2][3,3]。 我试图解决不重复的整数问题,但没有递归 但问题是我必须以递归的方式解决它,有什么想法吗?

  • 我正在尝试优化一个函数,给定一个N int数组,它返回一个元素和前一个元素之间的最小差异。显然,该函数仅适用于具有维度的数组 不知道有没有办法避免在main中传递第一个差,而是在递归函数中做所有的事情。我可以用stdio . h/stdlib . h/string . h/math . h作为头文件。非常感谢你的帮助,我希望这能让我对递归函数有更好的理解。