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

Модуль "Сортировки" • урок 4 из 17 •

Также упоминается как: метод пузырька, сортировка простым обменом (академическое название), сортировка обменами (exchange sort)

Суть урока. Пузырьковая сортировка: многократно сравнивает и меняет соседние элементы, пока самые "тяжелые" не всплывут в конец массива. O(N²), устойчивая, но очень медленная на практике.
Историческая справка: алгоритм, который знают все и не применяет никто

Метод обмена соседних элементов описан еще в 1956 году под именем sorting by exchange, а образное название "пузырьковая" закрепилось за ним только в начале шестидесятых.

Читать дальше

Одно из первых описаний метода дал Эдвард Френд в работе "Sorting on Electronic Computer Systems" (1956), где алгоритм назывался просто сортировкой обменами. Привычное Bubble Sort вошло в обиход позже: его употребляет Кеннет Айверсон, автор языка APL, в книге "A Programming Language" (1962). Кто произнес это слово первым, история не сохранила - у алгоритма нет одного изобретателя, слишком уж он очевиден. Каждый, кому нужно было упорядочить десяток чисел, придумывал его заново.

Дональд Кнут отозвался о нем беспощадно. В третьем томе "Искусства программирования" он пишет, что у пузырьковой сортировки нет ровно никаких достоинств, кроме броского названия и пары интересных теоретических задач, к которым она приводит. И это справедливо: сортировка вставкой при той же квадратичной сложности почти всегда оказывается быстрее.

Зато как учебный пример алгоритм пережил всех. В 2007 году на встрече в Google Эрик Шмидт спросил Барака Обаму, тогда кандидата в президенты, как эффективнее всего отсортировать миллион 32-битных целых чисел. "Думаю, пузырьковая сортировка тут точно не подойдет", - ответил Обама под смех зала.

Самый знаменитый учебный алгоритм. Основан на локальных обменах соседних элементов, которые постепенно приводят к глобальной упорядоченности.

Алгоритм работы

Пузырьковые сортировки: за каждый проход очередной наибольший элемент всплывает в конец массива, отсортированный хвост растет, а зона проверки сокращается (Bubble Sort)
Отсортированный хвост растет справа, поэтому каждый следующий проход короче предыдущего: 5 пар, 4, 3. Сумма 5 + 4 + 3 + ... и дает квадратичную сложность.

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

Тренажер: пузырьковая сортировка

Отсортируем массив 3 6 2 5 4 7 по возрастанию.

еще не на месте сравниваемая пара на своем месте
Сравнения: 0 Обмены: 0 Шаг: 0 / 0
.oO
Bubble Sort
Пузырьковая сортировка
Классика жанра: соседние элементы сравниваются и меняются местами, а наибольшие "всплывают" в конец массива.
Разобрать по шагам в большой версии →

Данный метод устойчив (если строго >, а не >=), но из-за огромного количества обменов на каждом шаге он крайне медленный на практике.

Другие пузырьковые сортировки

Обмен соседних элементов породил не один алгоритм, а целое семейство. Все они делают одно и то же и различаются лишь тем, в каком порядке перебирают пары - поэтому о пузырьковых сортировках говорят во множественном числе.

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

#include <stdbool.h>

void BubbleSort(int arr[], int n) {
    bool swapped;
    for (int i = 0; i < n - 1; i++) {
        swapped = false; // Флаг: были ли обмены в этом проходе?
        
        // Внутренний цикл до n-i-1, так как 'i' элементов уже всплыли в конец
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                Swap(&arr[j], &arr[j + 1]);
                swapped = true;
            }
        }
        // Если обменов не было, массив отсортирован - выходим досрочно!
        if (!swapped) break;
    }
}
Флаг swapped и ранний выход в пузырьковой сортировке: если за целый проход не было ни одного обмена, внешний цикл прерывается
Флаг swapped стоит ровно для того, чтобы отличить проход с обменами от прохода без них: во втором случае массив уже упорядочен и остальные проходы не нужны.

Коротко: главное

  • Алгоритм многократно проходит по массиву, сравнивая и обменивая соседние элементы.
  • За один полный проход наибольший из оставшихся элементов всплывает в конец массива.
  • Временная сложность сортировки составляет O(N²).
  • Алгоритм устойчив, но крайне медленен на практике из-за большого числа обменов.
  • Процесс можно оптимизировать: если за проход не было ни одного обмена, массив уже отсортирован.

Проверьте себя

В каком случае оптимизированный алгоритм досрочно завершает свою работу?

Как вам урок? Спасибо за отзыв!