【问题标题】:I have written a code of mergeSort(from clrs book) but not getting an output我写了一段mergeSort代码(来自clrs book)但没有得到输出
【发布时间】:2021-06-04 13:46:48
【问题描述】:

我参考了合并排序算法的clrs book of Introduction to Algorithms,并用C语言编写了一个程序。虽然我用笔和纸手动检查过,但代码似乎是正确的,但我也没有得到正确的输出。

输出如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void merge(int array[], int start, int middle, int end) {
    int n1 = middle - start + 1;
    int n2 = end - start;
    int i;
    int leftarray[n1 + 1], rightarray[n2 + 1];
    for (i = 0; i < n1; i++) {
        leftarray[i] = array[start + i];
    }
    for (int j = 0; i < n2; i++) {
        rightarray[j] = array[middle + j + 1];
    }
    leftarray[n1 + 1] = 1000000;
    rightarray[n2 + 1] = 1000000;
    
    int k, j = 0;
    i = 0;
    for (k = start; k <= end; k++) {
        if (leftarray[i] > rightarray[j]) {
            array[k] = rightarray[j];
            j++;
        } else {
            array[k] = leftarray[i];
            i++;
        }
    }
}

void mergeSort(int array[], int start, int end) {
    if (start < end) {
        int middle = (start + end) / 2;
        mergeSort(array, start, middle);
        mergeSort(array, middle + 1, end);
        merge(array, start, middle, end);   
    }
}

void sorting(int array[], int length) {
    int i;
    for (i = 0; i < length; i++) {
        printf("%d ", array[i]);
    }   
}

int main() {
    int noOfelements;
    scanf("%d", &noOfelements);
    int array[noOfelements];
    for (int i = 0; i < noOfelements; i++) {
        scanf("%d", &array[i]);
    }
    printf("Before Sorting: ");
    sorting(array, noOfelements);
    mergeSort(array, 0, noOfelements - 1);
    printf("After Sorting: ");
    sorting(array, noOfelements);
    return 0;   
}

上述程序的输出:

5
5 4 3 2 1 
Before Sorting: 5 4 3 2 1 After Sorting: 2 0 5 0 32

【问题讨论】:

  • 请不要将文字作为图片发布。直接将其作为文本复制到问题中。
  • @Sameer Vhatkar 例如,在此语句 printf("Before Sorting: "); 之后,您没有输出任何内容
  • @VladfromMoscow sorting 函数确实应该被称为 printArray
  • leftarray[n1+1] = 1000000; 嗯... 什么 ??除了没有意义之外,这些行还调用了未定义的行为。 VLA 的大小只有n1+1,因此只能索引到n1rightarray[n2+1] = 1000000;n2 也是如此。

标签: c algorithm mergesort


【解决方案1】:

虽然Thomas H Cormen、Charles E Leiserson、Ronald L Rivest 和 Clifford Stein 所著的算法简介一书被认为是一本优秀的教科书,但您实现的算法有几个缺点:

  • 它使用标记值的概念,即在要合并的数组末尾设置的值,据说比任何现有值都大,以希望简化合并过程。实际上,并没有像有任何这样的值,为什么它们不能作为常规值出现在数组中?
  • 它使用end作为数组中最后一个元素的索引:使用end作为数组外第一个元素的索引会简单得多,这样就不需要混淆+1/ -1 调整并允许空数组。
  • 您使用int middle = (start + end) / 2; 可能会溢出startend 的大值,尽管如果您尝试对如此庞大的数组进行排序,您的实现的其他部分将会失败。写int middle = start + (end - start) / 2; 仍然更安全

您的代码失败,因为您将标记值设置得太远。你应该写:

  leftarray[n1] = 1000000;
  rightarray[n2] = 1000000;

这是一个更好的方法:

#include <stdio.h>

void merge(int array[], int start, int middle, int end) {
    int n1 = middle - start;
    int i, j, k;

    // save the elements from the left half, no need to save the right half
    int leftarray[n1];
    for (i = 0; i < n1; i++) {
        leftarray[i] = array[start + i];
    }
    
    for (i = 0, j = middle, k = start; i < n1; k++) {
        if (j >= end || leftarray[i] <= array[j]) {
            array[k] = leftarray[i];
            i++;
        } else {
            array[k] = array[j];
            j++;
        }
    }
}

void mergeSort(int array[], int start, int end) {
    if (end - start >= 2) {
        int middle = start + (end - start) / 2;
        if (middle - start > 100000) {
            // avoid stack overflow: allocate at most 100k ints for `leftarray`
            middle = start + 100000;
        }
        mergeSort(array, start, middle);
        mergeSort(array, middle, end);
        merge(array, start, middle, end);   
    }
}

void print_array(const char *prefix, const int array[], int length) {
    printf("%s:", prefix);
    for (int i = 0; i < length; i++) {
        printf(" %d", array[i]);
    }
    printf("\n");
}

int main() {
    int noOfelements;
    if (scanf("%d", &noOfelements) != 1 || noOfelements < 0)
        return 1;
    int array[noOfelements];
    for (int i = 0; i < noOfelements; i++) {
        if (scanf("%d", &array[i]) != 1)
            return 1;
    }
    print_array("Before Sorting", array, noOfelements);
    mergeSort(array, 0, noOfelements);
    print_array("After Sorting", array, noOfelements);
    return 0;   
} 

【讨论】:

  • int middle = (start + end)/2 - 将其更改为 size_t middle = (start + end)/2 就足够了。在 32 位系统上,仅当 start+end > 2^32 时才会发生溢出,这意味着至少 end > 2^31 (2GB)。这只有在对大小大于 2GB 的字节数组进行排序时才会发生,这不太可能。在 64 位系统上,size_t 会超过内存大小。
  • @rcgldr:问题不在于middle的类型,而在于startend的类型。它们是int 变量,因此对于具有超过 10 亿个左右项目的数组确实会出现问题,这在 64 位系统上非常可行,其中类型 int 仍然只有 31 个值位。这个bug是经典的,它甚至出现在Python zlib extension module allowing for arbitrary code execution
  • 我应该解释说我建议在开始和结束时也使用 size_t。在 64 位系统上,它们将是 64 位无符号整数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多