我正在尝试实现一个可以使用整数,字符串和char的合并排序算法。不幸的是,当数组长度为奇数时,我发现它对整数不起作用。
例如:输入:2 2 3 7 1 2 1
。输出:2 2 3 7 0 1 1
。
现在我试图在我的代码中找到错误。这是:
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "MergeSort.h"
int StrCmp(char *st1, char *st2) {
char *str1 = st1, *str2 = st2;
while (*str1 == *str2 && *str1 != 0)
str1++, str2++;
return *str1 - *str2;
}
int CompareInt(void *a, void *b) {
return *(int *)a - *(int *)b;
}
int CompareChar(void *a, void *b) {
return *(char *)a - *(char *)b;
}
int CompareStr(const void *a, const void *b) {
return strcmp(*(char **)a, *(char **)b);
}
int merge(void *base, size_t num, size_t el_size, int (*compar)(const void*, const void*)) {
size_t size = (size_t)num / 2;
char *char_base = (char *)base;
char *first = malloc(size * el_size);
char *second = malloc((num - size) * el_size);
for (int i = 0; i < size; i++)
for (int j = 0; j < el_size; j++)
first[i * el_size + j] = char_base[i * el_size + j];
for (int i = 0; i < num - size; i++)
for (int j = 0; j < el_size; j++)
second[i * el_size + j] = char_base[size * el_size + i * el_size + j];
size_t i = 0, j = 0, c = 0;
while (i < size && j < num - size) {
if (compar(&first[i * el_size], &second[j * el_size]) <= 0) {
for (int k = 0; k < el_size; k++)
char_base[el_size * c + k] = first[i * el_size + k];
i++;
} else {
for (int k = 0; k < el_size; k++)
char_base[el_size * c + k] = second[j * el_size + k];
j++;
}
c++;
}
if (i == size) {
while (j < num - size) {
for (int k = 0; k < el_size; k++)
char_base[el_size * c + k] = second[j * el_size + k];
j++;
c++;
}
} else {
while (i < size) {
for (int k = 0; k < el_size; k++)
char_base[el_size * c + k] = first[i * el_size + k];
i++;
c++;
}
}
free(first);
free(second);
}
int merge_sort(void *base, size_t num, size_t el_size, int (*compar)(const void*, const void*)) {
if (num > 1) {
size_t s = num / 2;
char *char_base = base;
merge_sort(char_base, s, el_size, compar);
merge_sort(char_base + (num - s) * el_size, num - s, el_size, compar);
merge(char_base, num, el_size, compar);
}
}
int main() {
int nums[] = { 2, 2, 3, 7, 1, 2, 1 };
cmp_t cmp = CompareInt;
merge_sort(nums, 7, sizeof(int), cmp);
for (int i = 0; i < 7; i++)
printf("%i ", nums[i]);
return 0;
}
答案 0 :(得分:3)
错误在函数merge_sort()
中:第二次递归调用是在错误的基址上完成的:
merge_sort(char_base + (num - s) * el_size, num - s, el_size, compar);
修复是
merge_sort(char_base + s * el_size, num - s, el_size, compar);
请注意,您的代码中还有其他问题:
比较函数的签名不正确,应该使用const void *
个参数。
merge()
和merge_sort()
都应定义为void
,因为它们不会返回任何值。
CompareInt
无法处理差异超过INT_MAX
的大整数值,例如INT_MAX
和INT_MIN
。应写成:
int CompareInt(const void *a, const void *b) {
int na = *(const int *)a;
int nb = *(const int *)b;
return (nb < na) - (na < nb);
}
您应该在数字后打印'\n'
。
您还可以通过各种方式改进实施:
如果您将s
计算为(n + 1) / 2
,则可以使用更少的内存并实现更简单,更快速的实现,因为{{1}中不需要second
数组功能。
使用指针,可以大大减少乘法次数。
这是一个更简单的实现,具有相同的语义:
merge