Menu
Coddy logo textTech

Quick Sort

Последнее обновление

Быстрая сортировка — это алгоритм «разделяй и властвуй», который сортирует вокруг «опорного элемента» (pivot). Он выбирает опорный элемент, затем разбивает массив так, чтобы всё меньшее оказалось до него, а всё большее — после, что закрепляет опорный элемент на его окончательной отсортированной позиции. Затем он рекурсивно обрабатывает левую и правую части. Эта визуализация использует схему Ломуто с последним элементом в качестве опорного. Нажмите воспроизведение, чтобы увидеть разбиение и размещение опорного элемента.

Быстрая сортировка обычно является самой быстрой универсальной сортировкой на практике благодаря хорошей работе с кэшем и разбиению на месте, со средней сложностью O(n log n). Её худший случай — O(n²) (например, уже отсортированный массив при плохом выборе опорного элемента), которого позволяют избежать хорошие стратегии выбора опорного элемента, такие как медиана трёх или рандомизация.

Временная и пространственная сложность

СлучайСложностьПримечания
Лучший случайO(n log n)Сбалансированные разбиения
Средний случайO(n log n)Случайный порядок
Худший случайO(n²)Постоянно несбалансированные опорные элементы
ПамятьO(log n)Стек рекурсии (разбиение на месте)
УстойчиваяНетОбмены при разбиении переставляют равные элементы

Шаг за шагом

ШагЧто происходит
1Выберите опорный элемент (здесь — последний элемент диапазона).
2Разбиение: переместите все элементы меньше опорного влево от него.
3Поменяйте опорный элемент на границу — теперь он на своей окончательной позиции.
4Рекурсивно примените быструю сортировку к левой части.
5Рекурсивно примените быструю сортировку к правой части.

Разобранный пример

Сортировка [5, 2, 4, 1] по схеме Ломуто (последний элемент — опорный):

ПроходМассивДействие
Начало[5, 2, 4, 1]Разбить весь диапазон; опорный элемент — 1 (последний элемент).
1[1, 2, 4, 5]Ничего меньше 1 нет, поэтому меняем 1 на индекс 0; опорный 1 теперь окончателен. Рекурсия вправо по [2, 4, 5].
2[1, 2, 4, 5]Разбить [2, 4, 5] с опорным 5; и 2, и 4 меньше, поэтому 5 остаётся в конце и окончателен. Рекурсия влево по [2, 4].
3[1, 2, 4, 5]Разбить [2, 4] с опорным 4; 2 меньше, поэтому 4 остаётся на месте и окончателен. 2 — единственный элемент, поэтому уже отсортирован.
Готово[1, 2, 4, 5]Каждый опорный элемент закреплён на своём месте; массив отсортирован.

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

Используйте, когдаИзбегайте, когда
Нужна быстрая универсальная сортировка в памяти с малыми константами.Нужно гарантированное время O(n log n) в худшем случае (используйте пирамидальную или сортировку слиянием).
Памяти мало — разбиение выполняется на месте и требует лишь O(log n) стека.Нужна устойчивая сортировка, сохраняющая порядок равных ключей.
Данные в случайном или неизвестном порядке, и вы используете случайный опорный элемент или медиану трёх.Вход уже отсортирован или почти отсортирован, а опорный элемент фиксирован, что вызывает O(n²).
Важна локальность кэша, поскольку быстрая сортировка обращается к памяти последовательно.Вы сортируете связный список, где сортировка слиянием избегает произвольного доступа, на который опирается быстрая сортировка.

Код Quick Sort

Чистая, готовая к запуску реализация Quick Sort на Python, JavaScript, Java, C++, C. Выберите язык, скопируйте код или откройте его уже загруженным в плейграунде Coddy.

Код Quick Sort на Python

Python
1def quick_sort(a, low=0, high=None):2    if high is None:3        high = len(a) - 14    if low < high:5        p = partition(a, low, high)6        quick_sort(a, low, p - 1)7        quick_sort(a, p + 1, high)8    return a9
10
11def partition(a, low, high):12    # Lomuto partition: everything < pivot moves left of it13    pivot = a[high]14    i = low15    for j in range(low, high):16        if a[j] < pivot:17            a[i], a[j] = a[j], a[i]18            i += 119    a[i], a[high] = a[high], a[i]20    return i21
22
23nums = [10, 7, 8, 9, 1, 5]24print("Before:", nums)25quick_sort(nums)26print("After: ", nums)
Запустите этот код в плейграунде Python

Частые вопросы о Quick Sort

Какова временная сложность быстрой сортировки?
Быстрая сортировка в среднем O(n log n) и O(n log n) в лучшем случае, но деградирует до O(n²) в худшем случае, когда разбиения постоянно несбалансированны. Случайные опорные элементы или медиана трёх делают худший случай крайне маловероятным.
Устойчива ли быстрая сортировка?
Нет. Стандартное разбиение на месте меняет местами удалённые элементы, что может изменить относительный порядок равных ключей. Устойчивые варианты существуют, но отказываются от преимущества быстрой сортировки работать на месте.
Почему быстрая сортировка часто быстрее сортировки слиянием?
Быстрая сортировка разбивает на месте с превосходной локальностью кэша и без дополнительного буфера, поэтому её константы малы. Сортировка слиянием достигает той же оценки O(n log n), но платит буфером O(n) и большим перемещением данных.
Быстрая сортировка или сортировка слиянием — что выбрать?
Выбирайте быструю сортировку для быстрой сортировки массивов в памяти на месте, где её малые константы обычно побеждают. Выбирайте сортировку слиянием, когда нужна устойчивая сортировка, гарантированный худший случай O(n log n) или когда вы сортируете связные списки или внешние данные, не помещающиеся в ОЗУ.
Почему быстрая сортировка становится O(n²) на отсортированном массиве?
При фиксированном опорном элементе, таком как первый или последний, уже отсортированный вход приводит к тому, что каждое разбиение отделяет лишь один элемент, создавая n уровней рекурсии вместо log n. Выбор опорного элемента случайно или методом медианы трёх ломает этот шаблон и восстанавливает поведение O(n log n).
В чём разница между схемами разбиения Ломуто и Хоара?
Схема Ломуто использует один индекс, сканирующий слева направо, и её проще кодировать, поэтому эта визуализация использует именно её. Схема Хоара использует два указателя, движущихся навстречу, и обычно делает меньше обменов, что делает её быстрее на практике, но она не помещает опорный элемент на его окончательную позицию на шаге разбиения.
Coddy programming languages illustration

Освойте алгоритмы с Coddy

НАЧАТЬ