EasyТеория4 min

Базовые сортировки

Пузырьковая, выбором и вставками: реализация, сравнение и анализ

Зачем изучать простые сортировки?

Несмотря на то, что в реальном коде используются встроенные sort(), понимание базовых алгоритмов необходимо для: интервью, понимания более сложных алгоритмов, выбора алгоритма под конкретную задачу.

Пузырьковая сортировка (Bubble Sort)

Идея: сравниваем соседние элементы и меняем местами, если они в неправильном порядке. Большие элементы «всплывают» к концу.

<?php
declare(strict_types=1);

/** @param list<int> $arr */
function bubbleSort(array &$arr): void
{
    $n = count($arr);

    for ($i = 0; $i < $n; $i++) {
        $swapped = false;

        for ($j = 0; $j < $n - 1 - $i; $j++) {
            if ($arr[$j] > $arr[$j + 1]) {
                [$arr[$j], $arr[$j + 1]] = [$arr[$j + 1], $arr[$j]];
                $swapped = true;
            }
        }

        if (!$swapped) {
            break; // Array is already sorted
        }
    }
}
Визуализация (сортировка [5, 3, 8, 1, 2]):
Проход 1: [5,3,8,1,2] -> [3,5,8,1,2] -> [3,5,8,1,2] -> [3,5,1,8,2] -> [3,5,1,2,8]
Проход 2: [3,5,1,2,8] -> [3,5,1,2,8] -> [3,1,5,2,8] -> [3,1,2,5,8]
Проход 3: [3,1,2,5,8] -> [1,3,2,5,8] -> [1,2,3,5,8]
Проход 4: [1,2,3,5,8] -> нет обменов -> СТОП
Сложность Лучший Средний Худший
Время O(n) O(n²) O(n²)
Память O(1) O(1) O(1)
Стабильная Да

Сортировка выбором (Selection Sort)

Идея: на каждом шаге находим минимальный элемент и ставим на правильную позицию.

<?php
declare(strict_types=1);

/** @param list<int> $arr */
function selectionSort(array &$arr): void
{
    $n = count($arr);

    for ($i = 0; $i < $n; $i++) {
        $minIdx = $i;

        for ($j = $i + 1; $j < $n; $j++) {
            if ($arr[$j] < $arr[$minIdx]) {
                $minIdx = $j;
            }
        }

        [$arr[$i], $arr[$minIdx]] = [$arr[$minIdx], $arr[$i]];
    }
}
Визуализация:
[5, 3, 8, 1, 2]
 i=0: min=1(idx=3), swap -> [1, 3, 8, 5, 2]
 i=1: min=2(idx=4), swap -> [1, 2, 8, 5, 3]
 i=2: min=3(idx=4), swap -> [1, 2, 3, 5, 8]
 i=3: min=5(idx=3), no swap -> [1, 2, 3, 5, 8]
Сложность Лучший Средний Худший
Время O(n²) O(n²) O(n²)
Память O(1) O(1) O(1)
Стабильная Нет

Selection Sort делает минимальное количество обменов (n-1) — полезно, если swap дорогой.

Сортировка вставками (Insertion Sort)

Идея: берём элемент и вставляем его в правильное место среди уже отсортированной части. Как сортируешь карты в руке.

<?php
declare(strict_types=1);

/** @param list<int> $arr */
function insertionSort(array &$arr): void
{
    $n = count($arr);

    for ($i = 1; $i < $n; $i++) {
        $key = $arr[$i];
        $j = $i - 1;

        while ($j >= 0 && $arr[$j] > $key) {
            $arr[$j + 1] = $arr[$j];
            $j--;
        }

        $arr[$j + 1] = $key;
    }
}
Визуализация:
[5, 3, 8, 1, 2]
 |отсортировано|
 i=1: key=3, [5] > 3 -> сдвиг -> [3, 5, 8, 1, 2]
 i=2: key=8, 5 < 8 -> на месте -> [3, 5, 8, 1, 2]
 i=3: key=1, сдвиг 8,5,3 -> [1, 3, 5, 8, 2]
 i=4: key=2, сдвиг 8,5,3 -> [1, 2, 3, 5, 8]
Сложность Лучший Средний Худший
Время O(n) O(n²) O(n²)
Память O(1) O(1) O(1)
Стабильная Да

Insertion Sort лучший из базовых: O(n) на почти отсортированных данных, стабильный, in-place, низкий overhead.

Сравнительная таблица

Алгоритм Лучший Средний Худший Память Стабильный Adaptive
Bubble Sort O(n) O(n²) O(n²) O(1) Да Да
Selection Sort O(n²) O(n²) O(n²) O(1) Нет Нет
Insertion Sort O(n) O(n²) O(n²) O(1) Да Да

Adaptive — алгоритм быстрее на почти отсортированных данных.

Когда использовать базовые сортировки

  • Insertion Sort: маленькие массивы (n < 50), почти отсортированные данные, online-сортировка (данные приходят потоком)
  • Selection Sort: минимизация количества swap
  • Bubble Sort: образовательные цели (на практике не используется)

Запомни: Insertion Sort — единственная из базовых, которую стоит использовать на практике. Встроенные sort() в Python (Timsort) и Go (pattern-defeating quicksort) используют Insertion Sort для маленьких подмассивов. Все базовые сортировки — in-place, O(1) памяти.

Итоги

  1. Все базовые сортировки: O(n²) в среднем, O(1) памяти
  2. Insertion Sort лучший из трёх: adaptive, stable, O(n) на почти отсортированных
  3. Selection Sort: минимум swaps
  4. Bubble Sort: только для обучения
  5. На практике: sort() использует гибридные алгоритмы

Проверь себя

Массив [1, 2, 3, 4, 5] сортируется каждым из трёх алгоритмов. Какой завершится быстрее всего?

Какая из базовых сортировок НЕ является стабильной?

Какой результат после ОДНОГО прохода Bubble Sort для массива [5, 1, 4, 2, 8]?

Когда на практике имеет смысл использовать Insertion Sort вместо встроенного sort()?