c - 为什么这种优化会导致我的合并排序失败?

标签 c sorting optimization merge mergesort

我正在研究非递归归并排序,我想出了一个优化方法可以稍微加快它的速度。要点是,我不是合并到一个临时缓冲区然后每次都将其复制回数据位置,而是先在一个方向合并,然后在另一个方向合并。这应该可以完美地工作,因为缓冲区大小相同且数据相同。

但是,当我尝试这样做时,我的数组并没有完全排序。有一些项目,有时在最后,有时在中间,是不合适的。我在下面的示例中包含了我用来测试我的代码的函数。

我尽我所能制作 MWE,但测试需要几个辅助函数。

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

#define MIN(x, y) ((x) > (y) ? (y) : (x))
#define OPTIMIZE true // if true, then merge in alternating directions

void merge(int* src, int* dest, size_t start, size_t mid, size_t end);
void merge_sort(int* data, size_t length);

/* MERGESORT IMPLEMENTATION {{{1 */

void merge(int* src, int* dest, size_t start, size_t mid, size_t end) {
    int i, j, k;
    for (i = start, j = mid, k = start; i < mid && j < end; k++) {
        if (src[i] > src[j]) {
            dest[k] = src[j];
            j++;
        } else {
            dest[k] = src[i];
            i++;
        }
    }
    for (; i < mid; i++, k++) {
        dest[k] = src[i];
    }
    for (; j < end; j++, k++) {
        dest[k] = src[j];
    }
}

void merge_sort(int* data, size_t length) {
    int* buffer = malloc(length * sizeof(int));
    int swap = false;
    for (size_t i = 0; i < length; i++) {
        buffer[i] = data[i];
    }

#if OPTIMIZE
    for (size_t step = 1; step < length; step *= 2, swap = !swap) {
        int* src = swap ? buffer : data;
        int* dest = swap ? data : buffer;
        for (size_t i = 0; i < length - step; i += (step * 2)) {
            merge(src, dest, i, i + step, MIN(length, i + (step * 2)));
        }
    }
    if (swap) {
        for (size_t i = 0; i < length; i++) {
            data[i] = buffer[i];
        }
    }
#else
    for (size_t step = 1; step < length; step *= 2, swap = !swap) {
        int* src = data;
        int* dest = buffer;
        for (size_t i = 0; i < length - step; i += (step * 2)) {
            merge(src, dest, i, i + step, MIN(length, i + (step * 2)));
        }
        for (size_t i = 0; i < length; i++) {
            data[i] = buffer[i];
        }
    }
#endif

    free(buffer);
}

/* UTILITY FUNCTIONS {{{1 */

void check_sorted(int* data, size_t length) {
    for (size_t i = 0; i < length - 1; i++) {
        if (data[i] != i) {
            printf("%ld: %d\n", i, data[i]);
        }
    }
}

void shuffle(int* data, size_t length) {
    for (size_t i = 1; i < length; i++) {
        size_t index = rand() % (i + 1);
        int temp = data[index];
        data[index] = data[i];
        data[i] = temp;
    }
}

/* MAIN {{{1 */

int main() {
    size_t length = 200;
    int* data = malloc(length * sizeof(int));

    for (size_t i = 0; i < length; i++) {
        data[i] = (int)i;
    }
    shuffle(data, length);

    merge_sort(data, length);
    check_sorted(data, length);

    free(data);
    return 0;
}

最佳答案

这似乎有效。评论中指出的修复:

void merge_sort(int* data, size_t length) {
    int* buffer = malloc(length * sizeof(int));
    int swap = false;
    /*                                  ** removed the initial copy */

#if OPTIMIZE
    for (size_t step = 1; step < length; step *= 2, swap = !swap) {
        int* src = swap ? buffer : data;
        int* dest = swap ? data : buffer;
        size_t i;                       /* fix, using i in 2nd loop */
        for (i = 0; i < length - step; i += (step * 2)) {  /* fix (removed size_t) */
            merge(src, dest, i, i + step, MIN(length, i + (step * 2)));
        }
        for( ; i < length; i++)         /* fix, copy single run if present */
            dest[i] = src[i];           /* fix, copy single run if present */
    }
    if (swap) {
        for (size_t i = 0; i < length; i++) {
            data[i] = buffer[i];
        }
    }
#else

替代修复:

    for (size_t step = 1; step < length; step *= 2, swap = !swap) {
        int* src = swap ? buffer : data;
        int* dest = swap ? data : buffer;
        for (size_t i = 0; i < length; i += (step * 2)) {                        /* fix */
            merge(src, dest, i, MIN(length, i+step), MIN(length, i+(step * 2))); /* fix */
        }

关于c - 为什么这种优化会导致我的合并排序失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59515306/

相关文章:

c - Linux 内核模块 : Socket buffer (sk_buff->len) non-deterministic behaviour

c - 我如何监控 cookie 是否被发送到其来源域以外的域?

php - 使用 $_GET 和下拉列表传递变量

c# - OrderBy 可以为一个元素多次评估委托(delegate)吗?

javascript - 将数组拆分为 block / block 并对其进行一一操作

c++ - 使用 -g gcc 标志编译的程序是否比不使用 -g 编译的同一程序慢?

c - 如何从 C 中给定的 char 指针读取 4 个字节的数据

c++ - 合并 K 排序链表中的循环

function - 使用 F# 优化记录中的函数值访问

c - 矩阵分配的段错误错误