Сортировка слиянием

Сортировка слиянием (Merge Sort): стратегия «разделяй и властвуй», рекурсия, слияние двух отсортированных половин, код на Python, сложность O(n log n).

Сортировка слиянием использует принцип «разделяй и властвуй»: делит массив пополам, рекурсивно сортирует каждую половину, а затем сливает две упорядоченные части в одну.

Сложность: O(n log n) во всех случаях; O(n) дополнительной памяти.

Идея алгоритма

Представь стопку листов с числами. Делишь её пополам. Каждую половину снова делишь — и так до тех пор, пока не останутся стопки по одному листу (один лист всегда «упорядочен»). Затем сливаешь пары стопок, каждый раз беря наименьшее из двух вершин. В итоге получаешь одну полностью отсортированную стопку.

Пошаговый разбор

Массив [38, 27, 43, 3, 9, 82, 10]:

Разбивка:
[38, 27, 43, 3, 9, 82, 10]
[38, 27, 43]    [3, 9, 82, 10]
[38] [27,43]    [3,9] [82,10]
[38] [27][43]   [3][9] [82][10]

Слияние:
[27,43]  [3,9]  [10,82]
[27,38,43]      [3,9,10,82]
       [3,9,10,27,38,43,82]

Код

def merge_sort(arr):
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])

    return merge(left, right)


def merge(left, right):
    result = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result


data = [38, 27, 43, 3, 9, 82, 10]
print(merge_sort(data))

Вывод:

[3, 9, 10, 27, 38, 43, 82]

Сложность и свойства

Случай

Время

Память

Лучший

O(n log n)

O(n)

Средний

O(n log n)

O(n)

Худший

O(n log n)

O(n)

Алгоритм устойчивый: при слиянии одинаковые элементы берутся из левой половины первыми (условие <=). Требует O(n) дополнительной памяти для вспомогательных массивов — это его главный недостаток.

Почему O(n log n)? На каждом уровне рекурсии суммарная работа — O(n) (слияние). Уровней рекурсии — log₂n (столько раз делим пополам). Итого: n · log n.

Когда применять

  • Нужна гарантированная O(n log n) сортировка — merge sort не деградирует в O(n²) как quick sort.
  • Требуется устойчивость (например, сортировка объектов по нескольким полям).
  • Сортировка связных списков — для них merge sort предпочтительнее quick sort.
  • Данные не помещаются в память — внешняя сортировка основана на идее слияния.

Коротко

  • Merge sort делит массив пополам, рекурсивно сортирует каждую часть и сливает их.
  • O(n log n) во всех случаях — самая стабильная из классических сортировок.
  • Устойчивая, но требует O(n) дополнительной памяти.
  • Основа внешней сортировки и многих гибридных алгоритмов.
Проверьте себя
1. Какова гарантированная сложность сортировки слиянием?
AO(n²)
BO(n)
CO(n log n)
DO(log n)
2. Почему merge sort требует O(n) дополнительной памяти?
AИз-за рекурсивного стека
BПотому что создаёт вспомогательные массивы при слиянии
CПотому что хранит все элементы дважды
DПотому что неустойчивая
3. Является ли сортировка слиянием устойчивой?
AНет, из-за рекурсии
BНет, порядок меняется при слиянии
CДа, если брать элемент из левой половины при равенстве
DТолько в итеративном варианте
Поддержать проект