Получить доступ

Как работает быстрая сортировка и когда она работает медленно?

JuniorСортировки
Ещё спрашивают так:
  • Почему у быстрой сортировки худший случай O(n²)?
  • Как выбирать опорный элемент?
  • Что такое разбиение Ломуто и Хоара?
Коротко

Выбираем опорный элемент, разбиваем массив: меньшие — влево, большие — вправо, опорный встаёт на своё место; затем рекурсивно сортируем части.

  • В среднем O(n log n), на практике часто быстрее остальных: работает на месте, хорошо дружит с кэшем
  • Худший O(n²) — когда опорный всё время крайний: например, последний элемент на отсортированных данных

А ещё Защита: случайный опорный или медиана трёх; при глубокой рекурсии — переход на пирамидальную (introsort)

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Попробуйте сами

Сортировки по шагам: пузырёк, вставки, выбор, слияние, быстрая, пирамидальная

Подробно

Схема «разделяй и властвуй»:

  1. выбрать опорный элемент (pivot);
  2. разбиение (partition): переставить элементы так, чтобы слева были не больше опорного, справа — больше; опорный оказывается на своей итоговой позиции;
  3. рекурсивно отсортировать левую и правую части.

Разбиение выполняется на месте за O(n). Две известные схемы: Ломуто — проще, опорный — последний элемент; Хоара — два указателя навстречу, меньше обменов.

Почему O(n log n) в среднем. Если опорный делит массив примерно пополам, глубина рекурсии — log n уровней, на каждом суммарно O(n) работы.

Почему O(n²) в худшем. Если опорный каждый раз минимальный или максимальный, одна часть пустая, а другая меньше всего на один элемент: n уровней по O(n). Классический случай — опорный «последний элемент» на уже отсортированных или почти отсортированных данных. Ещё один — много одинаковых значений при наивном разбиении.

Как защищаются:

  • случайный опорный — худший случай становится крайне маловероятным;
  • медиана трёх (первый, средний, последний);
  • трёхпутевое разбиение для повторов (меньше, равно, больше);
  • introsort — при слишком глубокой рекурсии переключение на пирамидальную сортировку, что гарантирует O(n log n).

Быстрая сортировка неустойчива, дополнительная память — O(log n) на стек рекурсии (если сначала рекурсивно обрабатывать меньшую часть).

Пример

def quicksort(a, lo=0, hi=None):
    if hi is None:
        hi = len(a) - 1
    if lo >= hi:
        return
    pivot = a[hi]                      # Ломуто: опорный — последний
    i = lo - 1
    for j in range(lo, hi):
        if a[j] <= pivot:
            i += 1
            a[i], a[j] = a[j], a[i]
    a[i + 1], a[hi] = a[hi], a[i + 1]  # опорный на своё место
    quicksort(a, lo, i)
    quicksort(a, i + 2, hi)

Что хотят услышать

  • Опорный, разбиение, рекурсия.
  • Средняя сложность и почему.
  • Причина худшего случая и пример данных.
  • Способы защиты: случайный опорный, медиана трёх, introsort.

Частые ошибки

  • Не знать про худший случай O(n²).
  • Считать быструю сортировку устойчивой.

Что спросят дальше

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем