Menu
Coddy logo textTech

Куча (двоичная куча)

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

Двоичная куча - это полное двоичное дерево, которое держит наименьшее (min-heap) или наибольшее (max-heap) значение в корне. Эта визуализация - min-heap: каждый родитель меньше или равен своим потомкам. Чтобы добавить значение, его помещают в следующую свободную позицию, а затем «поднимают вверх», меняя местами с родителем, пока оно меньше, пока свойство кучи снова не выполнится. Нажмите воспроизведение выше, чтобы увидеть, как каждое новое значение всплывает на своё место.

Поскольку куча - это полное дерево, она компактно хранится в массиве: потомки узла i находятся в 2i+1 и 2i+2. Вставка и удаление минимума - O(log n) (один путь от корня к листу), а просмотр минимума - O(1), что и нужно очереди с приоритетом.

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

ОперацияСложностьПримечания
Просмотр мин/максO(1)Это всегда корень
Вставка (push)O(log n)Всплытие по одному пути
Удаление мин/максO(log n)Погружение по одному пути
Построение кучиO(n)Heapify за один раз
ПамятьO(n)На основе массива, без указателей

Пошагово (push)

ШагЧто происходит
1Добавьте новое значение в конец (следующий свободный лист).
2Сравните его с родителем.
3Если оно меньше (min-heap), поменяйте его вверх.
4Повторяйте, пока оно не перестанет быть меньше родителя или не достигнет корня.

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

Построение min-heap путём вставки [5, 3, 8, 1, 4] по одному значению за раз:

PushМассив после всплытияДействие
5[5]Первое значение становится корнем.
3[3, 5]3 < родителя 5, поэтому всплывает до корня.
8[3, 5, 8]8 > родителя 5, поэтому остаётся листом.
1[1, 3, 8, 5]1 < родителя 5, обмен; затем 1 < родителя 3, всплывает до корня.
4[1, 3, 8, 5, 4]4 > родителя 3, поэтому остаётся; минимум 1 остаётся в корне.

Когда использовать кучу

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

Код Heap (Priority Queue)

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

Код Heap (Priority Queue) на Python

Python
1class MinHeap:2    def __init__(self):3        self.data = []4
5    def push(self, value):6        # Append at the end, then bubble up to restore order7        self.data.append(value)8        i = len(self.data) - 19        while i > 0:10            parent = (i - 1) // 211            if self.data[parent] <= self.data[i]:12                break13            self.data[i], self.data[parent] = self.data[parent], self.data[i]14            i = parent15
16    def pop(self):17        # Move the last leaf to the root, then sift it down18        top = self.data[0]19        last = self.data.pop()20        if self.data:21            self.data[0] = last22            self._sift_down(0)23        return top24
25    def _sift_down(self, i):26        n = len(self.data)27        while True:28            smallest = i29            left, right = 2 * i + 1, 2 * i + 230            if left < n and self.data[left] < self.data[smallest]:31                smallest = left32            if right < n and self.data[right] < self.data[smallest]:33                smallest = right34            if smallest == i:35                return36            self.data[i], self.data[smallest] = self.data[smallest], self.data[i]37            i = smallest38
39
40heap = MinHeap()41for value in [5, 3, 8, 1, 9, 2]:42    heap.push(value)43
44print("Heap array:     ", heap.data)45print("Popped in order:", [heap.pop() for _ in range(6)])
Запустите этот код в плейграунде Python

Частые вопросы о кучах

Для чего используется куча?
Кучи реализуют очереди с приоритетом, на которых работают алгоритм кратчайшего пути Дейкстры, планировщики задач и симуляции событий. Они также являются движком heapsort. Каждый раз, когда вам многократно нужен наименьший или наибольший элемент из меняющегося набора, куча - подходящий инструмент.
В чём разница между кучей и двоичным деревом поиска?
Оба - двоичные деревья, но BST поддерживает полный порядок слева направо (что позволяет упорядоченный поиск), тогда как куча гарантирует лишь отношение родитель-потомок (мин или макс в корне). Куча даёт доступ O(1) к крайнему значению; BST даёт поиск O(log n) любого значения.
Почему куча хранится в массиве?
Поскольку куча всегда является полным двоичным деревом, её узлы идеально отображаются на индексы массива: потомки индекса i находятся в 2i+1 и 2i+2, а родитель - в (i-1)/2. Это избавляет от хранения указателей на потомков и даёт отличную производительность кеша.
Куча - это то же самое, что отсортированный массив?
Нет. Куча гарантирует только то, что каждый родитель меньше (min-heap) или больше (max-heap) своих потомков, поэтому братья и двоюродные узлы не имеют определённого порядка. Отсортированный массив полностью упорядочен, но вставка в него стоит O(n), тогда как куча вставляет за O(log n) и по-прежнему даёт мгновенный доступ к крайнему значению.
Когда мне использовать кучу вместо простой сортировки массива?
Обращайтесь к куче, когда данные постоянно меняются и вам нужен только текущий минимум или максимум - вставка и извлечение стоят по O(log n) каждая, против пересортировки всего массива. Если у вас статичный набор данных и нужны все элементы по порядку, одна сортировка O(n log n) проще и часто быстрее.
Занимает ли построение кучи из n элементов O(n log n)?
Нет, если строить её за один раз. Вставка n элементов по одному - O(n log n), но восходящий heapify, который погружает от последнего родителя к корню, выполняется в целом за O(n), потому что большинство узлов находятся у дна и погружаются лишь на короткое расстояние.
Coddy programming languages illustration

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

НАЧАТЬ