在merge_sort算法中,当参数为双精度类型列表时有效,但当其为整数类型列表时无效

时间:2019-04-06 07:50:00

标签: c mergesort

我想对int类型列表进行排序。但是当合并功能中的参数是double列表时,它可以工作!但不在int列表中时...

这里是排序功能。参数是int指针。

如果将int列表更改为double列表可以正常工作。

ex)int *a-> double *a

ex)int *l, *r1-> double *l, *r1

ex)l = (int *)calloc(n1+1,sizeof(int)), r1 = (int *)calloc(n2+1,sizeof(int)) -> l = (double *)calloc(n1+1,sizeof(double)) r1 = (double *)calloc(n2+1,sizeof(double))

void merge(int *a, int p, int q, int r) {
    int n1 = q - p + 1;
    int n2 = r - q;
    int *l, *r1;
    int i, j, k;

    l = (int *)calloc(n1 + 1, sizeof(int));
    r1 = (int *)calloc(n2 + 1, sizeof(int));

    for (i = 0; i < n1;i++)
        l[i] = a[p + i];
    for (j = 0; j < n2; j++)
        r1[j] = a[q + 1 + j];

    l[n1] = 10000;
    r1[n2] = 10000;

    i = 0;
    j = 0;

    for (k = p; k <= r; k++) {
        if (l[i] <= r1[j]) {
            a[k] = l[i];
            ++i;
        } else {
            a[k] = r1[j];
            ++j;
        }
    }
    return;
}

这是递归函数。直到列表的长度为1

ex)int *a -> double *a

void merge_sort(int *a, int p, int r) {
    if (p < r) {
        int q = (p + r) / 2;
        merge_sort(a, p, q);
        merge_sort(a, q + 1, r);
        merge(a, p, q, r);
    }
}

创建一个长度为10的列表,并将其放入mergesort函数中。然后打印列表。

int main(int argc, char *argv[]) {

    int i, *a[10];

    for (i = 0; i < 10; i++) {
        a[i] = rand() % 10 + 1;  
    }

    merge_sort(a, 0, 10);

    for (i = 0; i < 10; i++) {
        printf("%d ", a[i]);
    }
    return 0;
}

结果是

0 0 0 2 5 10 9 9 3 5

1 个答案:

答案 0 :(得分:0)

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

  • 如果要更改数组元素的类型,则必须在所有地方(包括main函数中进行更改),还必须更改printf格式。提高警告级别(gcc -Wall -Wextra -Werror)可以防止愚蠢的错误。
  • amain的定义不正确,应该为int a[10];,而不是指向int的指针数组。
  • 您将元素总数传递给mergesort()中的mainmerge_sort(a, 0, 10);,这意味着应排除合并排序中的r。那么merge_sort(a, q + 1, r);中的递归调用mergesort是不正确的,因为q应该排除在merge_sort(a, p, q);中,但应包括在下半部分。请改用merge_sort(a, q, r);
  • 您使用int q = (p + r) / 2;计算段的中间位置。您可能对大型数组有未定义的行为,因为q + r可能溢出类型int的范围。这是一个经典的错误,在有人将代码用于大型数组之前,几十年来可能不会被注意到。使用int q = p + (r - p) / 2;避免出现这种情况。
  • merge中的算法不正确:您假设数组中的所有值均为< 10000,这可能是无效的假设。该代码应处理所有可能的值。您应该测试索引变量以检测子数组的末尾并专门处理其他数组的剩余值。
  • 您不会释放merge中分配的数组,从而导致内存泄漏。
  • 为使更改元素类型更容易,您可以使用typedef

这是改进版:

#include <stdio.h>

#ifdef USE_DOUBLE
typedef double sorttype;
#else
typedef int sorttype;
#endif

void merge(sorttype *a, int p, int q, int r) {
    // merge subarrays a[p...q] and a[q...r]
    // upper bounds q and r are excluded
    int n1 = q - p;
    int n2 = r - q;
    sorttype *a1, *a2;
    int i, j, k;

    a1 = malloc(n1 * sizeof(*a1));
    a2 = malloc(n2 * sizeof(*a2));

    for (i = 0; i < n1; i++)
        a1[i] = a[p + i];
    for (j = 0; j < n2; j++)
        a2[j] = a[q + j];

    i = 0;
    j = 0;
    for (k = p; k < r; k++) {
        if (i < n1 && (j >= n2 || a1[i] <= a2[j])) {
            a[k] = a1[i];
            ++i;
        } else {
            a[k] = a2[j];
            ++j;
        }
    }
    free(a1);
    free(a2);
}

void merge_sort(sorttype *s, int p, int r) {
    if (r - p > 1) {
        int q = p + (r - p) / 2;
        merge_sort(s, p, q);
        merge_sort(s, q, r);
        merge(s, p, q, r);
    }
}

int main(int argc, char *argv[]) {

    sorttype a[10];
    int i;

    for (i = 0; i < 10; i++) {
        a[i] = 1 + rand() % 10;
    }

    merge_sort(a, 0, 10);

    for (i = 0; i < 10; i++) {
#ifdef USE_DOUBLE
        printf("%g ", a[i]);
#else
        printf("%d ", a[i]);
#endif
    }
    printf("\n");
    return 0;
}

int的输出:

1 3 4 4 5 8 9 9 10 10

double的输出:

1 3 4 4 5 8 9 9 10 10

请注意,尽管重新编译并重新运行了程序,但随机数却是相同的...您应使用srand(clock())尝试获得不同的伪随机序列。

还要注意,不需要分配a2来复制右边的子数组,因为合并操作不会覆盖右边一半尚未复制的元素。

此外,您应该测试分配失败并报告。

这是merge的改进版本:

void merge(sorttype *a, int p, int q, int r) {
    // merge subarrays a[p...q] and a[q...r]
    // upper bounds q and r are excluded
    int n1 = q - p;
    int n2 = r - q;
    sorttype *a1;
    int i, j, k;

    a1 = malloc(n1 * sizeof(*a1));
    if (a1 == NULL) {
        fprintf(stderr, "memory allocation failure\n");
        exit(1);
    }
    for (i = 0; i < n1; i++)
        a1[i] = a[p + i];

    i = 0;
    j = 0;
    for (k = p; i < n1 && k < r; k++) {
        if (j >= n2 || a1[i] <= a[q + j]) {
            a[k] = a1[i];
            ++i;
        } else {
            a[k] = a[q + j];
            ++j;
        }
    }
    free(a1);
}