Сортировка слиянием
Стабильная сортировка
«Сортировка слиянием» — бесплатный урок C Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C Academy содержит 4 уроков всего.
Стабильная сортировка
Сортировка слиянием — это алгоритм сортировки по принципу «разделяй и властвуй»: он делит массив пополам, сортирует каждую половину, а затем снова сливает их. Во всех случаях его сложность равна O(n log n), и он стабилен.
Шаг разделения
Рекурсивно делите массив в середине, пока в каждой части не останется по одному элементу. Один элемент тривиально отсортирован — это базовый случай.
Шаг слияния
Основная операция — слияние двух уже отсортированных последовательностей в одну. Перемещайтесь по обеим с помощью указателей-индексов и каждый раз копируйте следующим меньший первый элемент.
#include <stdio.h>
void merge(int a[], int lo, int mid, int hi, int tmp[]) {
int i = lo, j = mid + 1, k = lo;
while (i <= mid && j <= hi)
tmp[k++] = (a[i] <= a[j]) ? a[i++] : a[j++];
while (i <= mid) tmp[k++] = a[i++];
while (j <= hi) tmp[k++] = a[j++];
for (int t = lo; t <= hi; t++) a[t] = tmp[t];
}
int main(void) {
int a[] = {1, 4, 6, 2, 3, 5}; /* two sorted runs */
int tmp[6];
merge(a, 0, 2, 5, tmp);
for (int i = 0; i < 6; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}Почему сортировка стабильна
При слиянии используется a[i] <= a[j], поэтому при равенстве двух элементов сначала выбирается элемент из левой последовательности. Поскольку в левой последовательности находились элементы, стоявшие раньше, исходный порядок сохраняется.
Рекурсивный управляющий код
Сортировка слиянием рекурсивно обрабатывает каждую половину, а затем сливает их. Мы передаём общий временный буфер, чтобы не выделять память при каждом вызове.
#include <stdio.h>
void merge(int a[], int lo, int mid, int hi, int tmp[]) {
int i=lo, j=mid+1, k=lo;
while (i<=mid && j<=hi) tmp[k++] = (a[i]<=a[j]) ? a[i++] : a[j++];
while (i<=mid) tmp[k++]=a[i++];
while (j<=hi) tmp[k++]=a[j++];
for (int t=lo;t<=hi;t++) a[t]=tmp[t];
}
void msort(int a[], int lo, int hi, int tmp[]) {
if (lo >= hi) return;
int mid = lo + (hi - lo) / 2;
msort(a, lo, mid, tmp);
msort(a, mid + 1, hi, tmp);
merge(a, lo, mid, hi, tmp);
}
int main(void) {
int a[] = {5, 2, 9, 1, 3, 8, 4};
int tmp[7];
msort(a, 0, 6, tmp);
for (int i = 0; i < 7; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}Использование памяти
В отличие от быстрой сортировки, сортировке слиянием требуется дополнительная память O(n) для буфера слияния. Это её главный недостаток при работе с очень большими массивами в условиях ограниченной памяти.
Гарантированная сложность O(n log n)
Рекурсия всегда делит массив пополам, поэтому образуется log n уровней, а на каждом уровне сливаются n элементов. Таким образом, сложность сортировки слиянием равна O(n log n) в лучшем, среднем и худшем случаях, в отличие от быстрой сортировки.
Подсчёт уровней слияния
Количество уровней рекурсии равно ceil(log2 n). Вычислим его для нескольких размеров.
#include <stdio.h>
int levels(int n) {
int L = 0;
while (n > 1) { n = (n + 1) / 2; L++; }
return L;
}
int main(void) {
int sizes[] = {1, 2, 8, 100, 1000};
for (int i = 0; i < 5; i++)
printf("n=%d levels=%d\n", sizes[i], levels(sizes[i]));
return 0;
}Итеративная сортировка слиянием
Итеративный вариант сливает последовательности размера 1, затем 2, затем 4, удваивая размер на каждом проходе. Он полностью избегает рекурсии и хорошо подходит для связанных списков.
#include <stdio.h>
void merge(int a[], int lo, int mid, int hi, int tmp[]) {
int i=lo,j=mid+1,k=lo;
while(i<=mid&&j<=hi) tmp[k++]=(a[i]<=a[j])?a[i++]:a[j++];
while(i<=mid) tmp[k++]=a[i++];
while(j<=hi) tmp[k++]=a[j++];
for(int t=lo;t<=hi;t++) a[t]=tmp[t];
}
int main(void) {
int a[] = {5, 2, 9, 1, 3, 8}, n = 6, tmp[6];
for (int width = 1; width < n; width *= 2)
for (int lo = 0; lo < n - width; lo += 2 * width) {
int mid = lo + width - 1;
int hi = (lo + 2*width - 1 < n-1) ? lo + 2*width - 1 : n-1;
merge(a, lo, mid, hi, tmp);
}
for (int i = 0; i < n; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}Когда выбирать сортировку слиянием
Выбирайте сортировку слиянием, если Вам нужны:
- гарантированная сложность O(n log n) без неблагоприятных случаев
- стабильность
- сортировка связанных списков (произвольный доступ не требуется)
- внешняя сортировка данных, слишком больших для RAM
Сортировка слиянием и быстрая сортировка
Быстрая сортировка обычно работает быстрее на практике и выполняется на месте, но не является стабильной и может иметь неблагоприятный худший случай. Сортировка слиянием стабильна и имеет гарантированную оценку сложности, но использует дополнительную память. Выбирайте алгоритм с учётом Ваших ограничений.
Быстрая проверка
Проверьте, насколько хорошо Вы поняли сортировку слиянием.
Итоги
Вы изучили сортировку слиянием.
- Разделить пополам, отсортировать каждую часть, затем слить
- При равных ключах слияние сначала выбирает левый элемент, обеспечивая стабильность
- Гарантированная сложность O(n log n) во всех случаях
- Требуется дополнительная память O(n); алгоритм отлично подходит для связанных списков и внешней сортировки
Часто задаваемые вопросы
Урок «Сортировка слиянием» бесплатный?
Да — полный текст урока «Сортировка слиянием» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C Academy, подпишись на CoddyKit PRO. Курс C Academy содержит 4 уроков всего.
Чему я научусь в уроке «Сортировка слиянием»?
Стабильная сортировка Ты практикуешь C Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C Academy?
Предыдущий опыт не требуется. C Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Сортировка слиянием»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C Academy?
Да. Каждый урок C Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Сортировка пузырьком и вставками
- Быстрая сортировка
- Сортировка слиянием
- Использование qsort