【发布时间】:2020-04-18 06:47:48
【问题描述】:
我正在研究一种非递归合并排序,并且我提出了一种可以加快速度的优化。要点是,不是每次合并到临时缓冲区然后将其复制回数据位置,而是先在一个方向合并,然后再合并另一个方向。这应该可以完美运行,因为缓冲区大小相同且数据相同。
但是,当我尝试这个时,我的数组没有完全排序。有一些项目,有时在最后,有时在中间,是不合适的。我在下面的示例中包含了我用来测试我的代码的函数。
我尽我所能制作一个 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;
}
【问题讨论】:
-
这是我调试的方法。使用较小的
length(8 到 15 之间的值就足够了)。调用shuffle后,保存数组。然后排序和检查。如果检查失败,则打印保存的数组。这为您提供了一个示例数组,您知道该数组将失败。使用该数组,并使用调试器单步执行代码以查看发生了什么。 -
check_sorted函数中有一个错误:i < length - 1应该是i < length。代码没有检查数组的最后一个元素。
标签: c sorting optimization merge mergesort