Menu
Coddy logo textTech

Heap Sort

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

Пирамидальная сортировка рассматривает массив как двоичную кучу. Сначала она строит max-heap, чтобы наибольший элемент оказался в корне (индекс 0). Затем она многократно меняет корень местами с последним неотсортированным элементом - фиксируя максимум на его месте - и просеивает новый корень вниз, чтобы восстановить свойство кучи. Нажмите «воспроизвести» выше, чтобы увидеть построение кучи и извлечения.

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

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

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

Пошагово

ШагЧто происходит
1Построить max-heap из массива (просеивать вниз, начиная с последнего родителя).
2Поменять корень (максимум) местами с последним элементом кучи.
3Уменьшить кучу на один - эта последняя ячейка теперь отсортирована.
4Просеять новый корень вниз, чтобы восстановить свойство max-heap.
5Повторять, пока в куче не останется один элемент.

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

Сортировка [3, 1, 6, 5, 2, 4]. Черта | отмечает границу между уменьшающейся кучей и отсортированным хвостом:

ПроходМассивДействие
Построение кучи[6, 5, 4, 1, 2, 3]Просеять вниз от последнего родителя, чтобы построить max-heap; 6 теперь в корне.
1[5, 3, 4, 1, 2 | 6]Поменять корень 6 с последней ячейкой, уменьшить кучу и просеять 3 вниз.
2[4, 3, 2, 1 | 5, 6]Извлечь корень 5, затем просеять 2 вниз, чтобы 4 поднялся в корень.
3[3, 1, 2 | 4, 5, 6]Извлечь корень 4, затем просеять 1 вниз, чтобы 3 поднялся в корень.
4[2, 1 | 3, 4, 5, 6]Извлечь корень 3; 2 уже удовлетворяет свойству кучи.
5[1 | 2, 3, 4, 5, 6]Извлечь корень 2; остаётся один элемент, поэтому массив отсортирован.

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

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

Код Heap Sort

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

Код Heap Sort на Python

Python
1def heap_sort(a):2    n = len(a)3    # Build a max-heap, deepest parent first4    for i in range(n // 2 - 1, -1, -1):5        sift_down(a, i, n)6    # Repeatedly move the max to the end and shrink the heap7    for end in range(n - 1, 0, -1):8        a[0], a[end] = a[end], a[0]9        sift_down(a, 0, end)10    return a11
12
13def sift_down(a, i, size):14    while True:15        largest = i16        left, right = 2 * i + 1, 2 * i + 217        if left < size and a[left] > a[largest]:18            largest = left19        if right < size and a[right] > a[largest]:20            largest = right21        if largest == i:22            return23        a[i], a[largest] = a[largest], a[i]24        i = largest25
26
27nums = [12, 11, 13, 5, 6, 7]28print("Before:", nums)29heap_sort(nums)30print("After: ", nums)
Запустите этот код в плейграунде Python

Часто задаваемые вопросы о пирамидальной сортировке

Какова временная сложность пирамидальной сортировки?
Пирамидальная сортировка составляет O(n log n) в лучшем, среднем и худшем случаях. Построение кучи — это O(n), а каждое из n извлечений стоит O(log n). Она использует O(1) дополнительной памяти.
Устойчива ли пирамидальная сортировка?
Нет. Операция просеивания вниз может переставить равные элементы друг относительно друга, поэтому пирамидальная сортировка не сохраняет относительный порядок равных ключей.
Когда следует использовать пирамидальную сортировку?
Используйте пирамидальную сортировку, когда нужен гарантированный худший случай O(n log n) при всего O(1) дополнительной памяти. Она избегает риска O(n²) быстрой сортировки без буфера O(n) сортировки слиянием, ценой устойчивости и производительности кэша.
В чём разница между пирамидальной и быстрой сортировкой?
Обе сортируют на месте, но у быстрой сортировки худший случай O(n²), тогда как пирамидальная гарантирует O(n log n). На практике быстрая сортировка обычно быстрее из-за лучшей локальности кэша и меньшего числа перестановок, поэтому пирамидальную выбирают в основном тогда, когда граница худшего случая должна быть гарантирована.
Как пирамидальная сортировка связана с очередью с приоритетом?
Двоичная куча — это стандартная реализация очереди с приоритетом, а пирамидальная сортировка по сути состоит в многократном извлечении максимума из этой очереди. Если ваши данные уже хранятся в куче, извлечение элементов по одному даёт вам отсортированный порядок бесплатно.
Нужна ли пирамидальной сортировке max-heap или min-heap?
Чтобы сортировать по возрастанию на месте, используйте max-heap: наибольший элемент на каждом проходе меняется в конец, а отсортированный хвост растёт справа. Min-heap дал бы убывающий порядок на месте или возрастающий, если извлекать в отдельный массив.
Coddy programming languages illustration

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

НАЧАТЬ