Этот код показывает, как я инструментировал алгоритм. Первоначально это было сделано с безусловными вызовами printf()
и dump_array()
- когда он работал, они были преобразованы в макросы, чтобы код можно было скомпилировать с помощью -DDEBUG
для получения подробной трассировки или без, чтобы просто получить результат.
Я не удалил код подсказки, но мои собственные программы этого не сделали. Возможно, я бы также подсчитал, сколько значений было введено программой (используя динамическое выделение памяти c, чтобы освободить место для данных), и просто считывал данные, пока они не достигнут EOF. Для тестирования я использовал три набора случайно сгенерированных чисел, сохраненных в файлах, чтобы тесты можно было повторять.
Я не пытался исправить исходный код merge()
- я просто переписал его. Мои комментарии к вопросу обрисовывают в общих чертах некоторые проблемы с оригинальным кодом. Я вполне уверен, что код в вопросе не уделяет достаточного внимания, какие диапазоны чисел действительны. Этот код комментирует, что диапазоны до mergesort()
и merge()
включают конечные индексы (следовательно, main()
вызывает mergesort(a, 0, n - 1)
, а не mergesort(a, 0, n)
, как, например, в вопросе).
Это код слияния сначала копирует данные в массив b
, а затем сливается из b
обратно в a
(более или менее как код в вопросе) - было бы целесообразно объединить в b
, а затем скопировать из b
до a
снова.
#include <assert.h>
#include <stdio.h>
#define MAX 1000
#ifdef DEBUG
#define TRACE(...) printf(__VA_ARGS__)
#define DUMP(t, a, l, r) dump_array(t, a, l, r)
#else
#define TRACE(...) ((void)0)
#define DUMP(t, a, l, r) ((void)0)
#endif
/* Dump elements in range l <= i <= r */
static void dump_array(const char *tag, int a[], int l, int r)
{
assert(tag != 0 && a != 0 && l >= 0 && l <= r);
printf("%s[%d..%d]:", tag, l, r);
for (int i = l; i <= r; i++)
printf(" %d", a[i]);
putchar('\n');
}
/* Merge elements in ranges l <= i <= m and m+1 <= j <= r */
static void merge(int a[], int l, int m, int r)
{
assert(a != 0 && l >= 0 && l <= m && m <= r);
TRACE("-->> %s(): %d..%d..%d\n", __func__, l, m, r);
int b[r + 1];
for (int i = l; i <= r; i++)
b[i] = a[i];
DUMP("b", b, l, r);
int k = l;
int i = l;
int j = m + 1;
while (i <= m && j <= r)
{
if (b[i] <= b[j])
a[k++] = b[i++];
else
a[k++] = b[j++];
}
while (i <= m)
a[k++] = b[i++];
while (j <= r)
a[k++] = b[j++];
DUMP("a", a, l, r);
TRACE("<<-- %s(): %d..%d..%d\n", __func__, l, m, r);
}
/* Sort elements in range l <= i <= r */
static void mergesort(int a[], int l, int r)
{
assert(a != 0 && l >= 0 && l <= r);
if (r > l)
{
TRACE("-->> %s(): %d..%d\n", __func__, l, r);
DUMP("a", a, l, r);
int mid = (l + r) / 2;
mergesort(a, l, mid);
DUMP("a", a, l, mid);
mergesort(a, mid + 1, r);
DUMP("a", a, mid+1, r);
merge(a, l, mid, r);
DUMP("a", a, l, r);
TRACE("<<-- %s(): %d..%d\n", __func__, l, r);
}
}
int main(void)
{
int n;
int a[MAX];
printf("Enter the number of elements you want to create: ");
if (scanf("%d", &n) != 1 || n < 1 || n > MAX)
{
fprintf(stderr, "read error\n");
return 1;
}
for (int i = 0; i < n; i++)
{
printf("Enter your number %d: ", i);
if (scanf("%d", &a[i]) != 1)
{
fprintf(stderr, "read error\n");
return 1;
}
}
putchar('\n');
dump_array("Unsorted", a, 0, n - 1);
mergesort(a, 0, n - 1);
dump_array("Sorted", a, 0, n - 1);
return 0;
}
Пример выполнения (-DDEBUG
; набор данных из 5 элементов - которые печатаются, конечно, для проверки):
Enter the number of elements you want to create: Enter your number 0: Enter your number 1: Enter your number 2: Enter your number 3: Enter your number 4:
Unsorted[0..4]: 17 74 63 62 26
-->> mergesort(): 0..4
a[0..4]: 17 74 63 62 26
-->> mergesort(): 0..2
a[0..2]: 17 74 63
-->> mergesort(): 0..1
a[0..1]: 17 74
a[0..0]: 17
a[1..1]: 74
-->> merge(): 0..0..1
b[0..1]: 17 74
a[0..1]: 17 74
<<-- merge(): 0..0..1
a[0..1]: 17 74
<<-- mergesort(): 0..1
a[0..1]: 17 74
a[2..2]: 63
-->> merge(): 0..1..2
b[0..2]: 17 74 63
a[0..2]: 17 63 74
<<-- merge(): 0..1..2
a[0..2]: 17 63 74
<<-- mergesort(): 0..2
a[0..2]: 17 63 74
-->> mergesort(): 3..4
a[3..4]: 62 26
a[3..3]: 62
a[4..4]: 26
-->> merge(): 3..3..4
b[3..4]: 62 26
a[3..4]: 26 62
<<-- merge(): 3..3..4
a[3..4]: 26 62
<<-- mergesort(): 3..4
a[3..4]: 26 62
-->> merge(): 0..2..4
b[0..4]: 17 63 74 26 62
a[0..4]: 17 26 62 63 74
<<-- merge(): 0..2..4
a[0..4]: 17 26 62 63 74
<<-- mergesort(): 0..4
Sorted[0..4]: 17 26 62 63 74
Пробный прогон (-UDEBUG
с 12 элементами - набор из 5 элементов использует первые 5 чисел из этого набора):
Enter the number of elements you want to create: Enter your number 0: Enter your number 1: Enter your number 2: Enter your number 3: Enter your number 4: Enter your number 5: Enter your number 6: Enter your number 7: Enter your number 8: Enter your number 9: Enter your number 10: Enter your number 11:
Unsorted[0..11]: 17 74 63 62 26 16 15 86 80 17 35 69
Sorted[0..11]: 15 16 17 17 26 35 62 63 69 74 80 86
Пробный прогон (-UDEBUG
с 30 элементами - отдельный набор случайные числа в целом):
Enter the number of elements you want to create: Enter your number 0: Enter your number 1: Enter your number 2: Enter your number 3: Enter your number 4: Enter your number 5: Enter your number 6: Enter your number 7: Enter your number 8: Enter your number 9: Enter your number 10: Enter your number 11: Enter your number 12: Enter your number 13: Enter your number 14: Enter your number 15: Enter your number 16: Enter your number 17: Enter your number 18: Enter your number 19: Enter your number 20: Enter your number 21: Enter your number 22: Enter your number 23: Enter your number 24: Enter your number 25: Enter your number 26: Enter your number 27: Enter your number 28: Enter your number 29:
Unsorted[0..29]: 80 76 86 10 46 99 12 55 76 34 86 23 76 83 13 21 93 50 19 53 86 92 81 35 90 53 65 67 79 20
Sorted[0..29]: 10 12 13 19 20 21 23 34 35 46 50 53 53 55 65 67 76 76 76 79 80 81 83 86 86 86 90 92 93 99
Я проверил набор из 30 элементов - взял список несортированных чисел, отсортировал их по sort -n
и сравнил этот список с отсортированным выводом. Результат был идентичным, что означает, что свойства сортировки «порядок» и «сохранение» были действительны. Я оценил результаты для наборов 5 и 12 значений данных.