合并排序的效率差,不受编译器优化影响

发布于 2025-01-24 13:15:06 字数 1655 浏览 0 评论 0原文

在尝试测量各种排序算法的时间需要对无符号整数的随机数组进行分类时,我获得了一些关于自上而下合并排序的特殊行为,这些行为似乎并非由不良的实现引起。

在长度高达100万个值的阵列上,合并排序的行为比随机pivot QuickSort甚至外壳排序都最差。这是出乎意料的,所以我尝试了多个在线合并Sort的实现,但是结果似乎仍然大致相同。

图1,优化

这是我用于这些图形的实现:

void merge(int *array, int l, int m, int r) {
    int i, j, k, nl, nr;
    nl = m - l + 1; nr = r - m;
    int *larr = new int[nl], *rarr = new int[nr];

    for (i = 0; i < nl; i++)
        larr[i] = array[l + i];
    for (j = 0; j < nr; j++)
        rarr[j] = array[m + 1 + j];

    i = 0; j = 0; k = l;
    while (i < nl && j < nr) {
        if (larr[i] <= rarr[j]) {
            array[k] = larr[i];
            i++;
        }
        else {
            array[k] = rarr[j];
            j++;
        }
        k++;
    }
    while (i < nl) {
        array[k] = larr[i];
        i++; k++;
    }
    while (j < nr) {
        array[k] = rarr[j];
        j++; k++;
    }

    delete[] larr;
    delete[] rarr;
}

void mergeSort(int *array, int l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        mergeSort(array, l, m);
        mergeSort(array, m + 1, r);
        merge(array, l, m, r);
    }
}

我也尝试过删除编译器的优化(可视++ 15),偏爱尺寸而不是速度,这似乎影响了所有其他算法而不是合并排序。尽管如此,它仍然是最糟糕的。

图2,优化

唯一的时间合并排序没有给出最糟糕的时间用1500万个元素的阵列进行测试,其性能比堆的阵列要好得多,但与其他元素相去甚远。

我绘制的值是带有随机数组的100个测试的平均值,因此我认为这只是一种特殊情况。我也认为在合并中使用动态内存是这些结果的原因,这些测试和其他所有内容都足够了。

有人知道为什么合并排序行为如此糟糕吗?为什么编译器优化似乎不会影响合并排序?

While trying to measure the time various sorting algorithms require to sort a random array of unsigned integers, I've obtained some peculiar behavior regarding top-down Merge sort that doesn't seem to be caused by bad implementation.

On arrays of length up to 1 million values, Merge sort behaves a lot worst than random-pivot Quicksort and even Shell sort. This is unexpected so I've tried with multiple online implementations of Merge sort but the result still seems to be about the same.

Graph 1, optimizations ON

This is the implementation I used for these graphs:

void merge(int *array, int l, int m, int r) {
    int i, j, k, nl, nr;
    nl = m - l + 1; nr = r - m;
    int *larr = new int[nl], *rarr = new int[nr];

    for (i = 0; i < nl; i++)
        larr[i] = array[l + i];
    for (j = 0; j < nr; j++)
        rarr[j] = array[m + 1 + j];

    i = 0; j = 0; k = l;
    while (i < nl && j < nr) {
        if (larr[i] <= rarr[j]) {
            array[k] = larr[i];
            i++;
        }
        else {
            array[k] = rarr[j];
            j++;
        }
        k++;
    }
    while (i < nl) {
        array[k] = larr[i];
        i++; k++;
    }
    while (j < nr) {
        array[k] = rarr[j];
        j++; k++;
    }

    delete[] larr;
    delete[] rarr;
}

void mergeSort(int *array, int l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        mergeSort(array, l, m);
        mergeSort(array, m + 1, r);
        merge(array, l, m, r);
    }
}

I have also tried to remove compiler optimizations (VisualC++15), favoring size instead of speed and this seem to have affected all the other algorithms instead of Merge sort. Nonetheless, it still got the worst time.

Graph 2, optimizations OFF

The only time Merge sort didn't give the worst time was on a test with arrays of 15 million elements where it got just a slightly better performance than Heap sort, but still far from the others.

The values that I plot are the averages of 100 tests with random arrays so I don't think this is just a particular case. I also don't think the use of dynamic memory in Merge sort is the cause of these results, 16GB of RAM are plenty for these tests and everything else.

Does anybody know why Merge sort behaves so badly and why compiler optimizations don't seem to affect Merge sort?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文