Бинарная куча¶
Бинарная куча — это структура данных, представляющая собой полное бинарное дерево, в котором каждый родительский узел имеет значение, не меньшее (для max-кучи) или не большее (для min-кучи) значений его дочерних узлов. Бинарная куча является частным случаем кучи (пирамиды) и широко применяется для реализации очередей с приоритетом, алгоритмов сортировки (например, пирамидальной сортировки) и в задачах, требующих быстрого доступа к максимальному или минимальному элементу.
¶Основные свойства
Бинарная куча характеризуется двумя ключевыми свойствами:
- Свойство кучи (heap property): Для любого узла
i(кроме корня) выполняется одно из двух условий:
- Max-куча:
A[parent(i)] >= A[i]— значение родительского узла не меньше значения дочернего. Корень содержит максимальный элемент. - Min-куча:
A[parent(i)] <= A[i]— значение родительского узла не больше значения дочернего. Корень содержит минимальный элемент.
- Свойство полноты (shape property): Дерево является полным бинарным деревом. Это означает, что все уровни, кроме, возможно, последнего, полностью заполнены, а на последнем уровне все узлы располагаются слева направо без пропусков.
Благодаря свойству полноты, бинарную кучу удобно хранить в виде одномерного массива. При индексации с 1 (или 0) для узла с индексом i:
- Родитель:
parent(i) = floor(i/2)(илиfloor((i-1)/2)при индексации с 0). - Левый дочерний узел:
left(i) = 2i(или2i + 1). - Правый дочерний узел:
right(i) = 2i + 1(или2i + 2).
Высота бинарной кучи, содержащей n элементов, равна O(log n), что обеспечивает логарифмическую сложность основных операций.
¶Основные операции
Базовые операции над бинарной кучей реализуются с помощью вспомогательных процедур, поддерживающих её свойства.
¶Вспомогательные процедуры
heapify(просеивание вниз): Восстанавливает свойство кучи для узлаi, если его дочерние деревья являются кучами. Процедура сравнивает значение узлаiс его дочерними узлами и, при нарушении свойства, меняет его местами с наибольшим (для max-кучи) или наименьшим (для min-кучи) дочерним узлом. Затем рекурсивно или итеративно применяется к тому дочернему узлу, с которым произошёл обмен. Сложность:O(log n).siftUp(просеивание вверх): Используется, когда значение узла становится больше (для max-кучи) или меньше (для min-кучи) значения родителя. Узел меняется местами с родителем, и процесс повторяется до корня или до восстановления свойства кучи. Сложность:O(log n).
¶Основные операции
insert(вставка): Добавляет новый элемент в конец массива (на последний уровень кучи), а затем применяет к нему процедуруsiftUpдля восстановления свойства кучи. Сложность:O(log n).extractMax/extractMin(извлечение максимального/минимального элемента): Извлекает корневой элемент (максимальный в max-куче или минимальный в min-куче). Корень заменяется последним элементом массива, размер кучи уменьшается на единицу. Затем к новому корню применяется процедураheapify. Сложность:O(log n).peek/getMax/getMin(получение корня без удаления): Возвращает значение корневого элемента. Сложность:O(1).buildHeap(построение кучи): Преобразует неупорядоченный массив в бинарную кучу. Эффективный способ заключается в последовательном примененииheapifyко всем внутренним узлам, начиная с последнего и двигаясь к корню. Сложность:O(n).increaseKey/decreaseKey(изменение ключа): Изменяет значение ключа узла. После изменения применяетсяsiftUp(если ключ был увеличен в max-куче или уменьшен в min-куче) илиheapify(в обратном случае). Сложность:O(log n).delete(удаление произвольного элемента): Удаляет элемент по известному индексу. Для этого значение ключа узла делается максимально возможным (для max-кучи) или минимально возможным (для min-кучи), затем выполняетсяsiftUpдо корня, после чего вызываетсяextractMax/extractMin. Сложность:O(log n).
¶Пирамидальная сортировка (Heapsort)
Бинарная куча лежит в основе алгоритма пирамидальной сортировки. Алгоритм состоит из двух этапов:
- Построение max-кучи из исходного массива (
buildHeap). - Повторное извлечение корневого элемента (
extractMax) и помещение его в конец отсортированной части массива. После каждого извлечения размер кучи уменьшается, а свойство кучи восстанавливается.
Сложность пирамидальной сортировки составляет O(n log n) в худшем, среднем и лучшем случаях. Она не требует дополнительной памяти (сортировка на месте), но не является устойчивой (stable).
¶Реализация
Ниже приведён пример реализации max-кучи на языке C++ с использованием массива (индексация с 0):
```cpp
¶include <iostream>
¶include <vector>
¶include <algorithm>
class MaxHeap { private: std::vector<int> heap;
int parent(int i) { return (i - 1) / 2; } int left(int i) { return 2 i + 1; } int right(int i) { return 2 i + 2; }
void heapify(int i) { int largest = i; int l = left(i); int r = right(i);
if (l < heap.size() && heap[l] > heap[largest]) largest = l; if (r < heap.size() && heap[r] > heap[largest]) largest = r;
if (largest != i) { std::swap(heap[i], heap[largest]); heapify(largest); } }
void siftUp(int i) { while (i > 0 && heap[parent(i)] < heap[i]) { std::swap(heap[i], heap[parent(i)]); i = parent(i); } }
public: void insert(int value) { heap.push_back(value); siftUp(heap.size() - 1); }
int extractMax() { if (heap.empty()) throw std::out_of_range("Heap is empty"); int max = heap[0]; heap[0] = heap.back(); heap.pop_back(); if (!heap.empty()) heapify(0); return max; }
int getMax() { if (heap.empty()) throw std::out_of_range("Heap is empty"); return heap[0]; }
void buildHeap(const std::vector<int>& arr) { heap = arr; for (int i = heap.size() / 2 - 1; i >= 0; --i) { heapify(i); } }
bool isEmpty() { return heap.empty(); } int size() { return heap.size(); }
void print() { for (int val : heap) std::cout << val << " "; std::cout << std::endl; } }; ```
¶Применение
Бинарная куча используется в различных областях информатики и программирования:
- Очереди с приоритетом: Бинарная куча — классическая реализация очереди с приоритетом, где элемент с наивысшим приоритетом (максимальный или минимальный) всегда находится в корне.
- Алгоритмы на графах: Алгоритм Дейкстры для поиска кратчайших путей и алгоритм Прима для построения минимального остовного дерева могут быть эффективно реализованы с использованием бинарной кучи для извлечения вершины с минимальным расстоянием.
- Сортировка: Пирамидальная сортировка (Heapsort) — один из основных алгоритмов сортировки, гарантирующий сложность
O(n log n). - Поиск k-го наибольшего/наименьшего элемента: С помощью min-кучи размера
kможно найтиk-й наибольший элемент заO(n log k). - Слияние отсортированных массивов: Бинарная куча позволяет эффективно слить несколько отсортированных массивов в один.
- Планирование задач: В операционных системах и системах реального времени для управления задачами с приоритетами.
¶Разновидности и расширения
Существуют модификации и обобщения бинарной кучи, улучшающие её характеристики или адаптирующие для специфических задач:
- d-куча (d-арная куча): Обобщение, в котором каждый узел имеет до
dдочерних узлов. Уменьшает высоту дерева доO(log_d n), что может ускоритьheapify, но замедляетsiftUp. - Биномиальная куча: Структура, состоящая из набора биномиальных деревьев. Поддерживает эффективное слияние двух куч (за
O(log n)). - Куча Фибоначчи: Более сложная структура, обеспечивающая амортизированное время
O(1)для вставки, изменения ключа и слияния, иO(log n)для извлечения минимума. Используется в продвинутых реализациях алгоритмов на графах. - Двусторонняя куча (deap): Структура, позволяющая быстро получать и максимальный, и минимальный элементы.
- Медианная куча: Структура, поддерживающая быстрое получение медианы набора данных.
¶Критика и ограничения
- Отсутствие эффективного поиска: Бинарная куча не поддерживает быстрый поиск произвольного элемента (кроме корня). Для поиска элемента по значению требуется линейный проход по массиву.
- Неустойчивость: Пирамидальная сортировка и другие алгоритмы на основе кучи не являются устойчивыми, то есть не сохраняют относительный порядок равных элементов.
- Ограниченная поддержка слияния: Слияние двух бинарных куч требует перестроения одной из них за
O(n), что менее эффективно, чем у биномиальных куч или куч Фибоначчи.
¶Источники
- Кормен Т., Лейзерсон Ч., Ривест Р., Штайн К. Алгоритмы: построение и анализ. — 3-е изд. — М.: Вильямс, 2013. — 1328 с.
- Седжвик Р. Фундаментальные алгоритмы на C++. Анализ/Структуры данных/Сортировка/Поиск. — М.: ДиаСофт, 2002. — 688 с.
- Кнут Д. Э. Искусство программирования. Том 3. Сортировка и поиск. — 2-е изд. — М.: Вильямс, 2007. — 832 с.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


