Открыть сервис

Куча

Куча — это структура данных, представляющая собой специализированное дерево, удовлетворяющее свойству кучи: для любого узла значение ключа (приоритета) этого узла не меньше (или не больше) значений ключей его потомков. Кучи являются частным случаем приоритетных очередей и широко применяются в алгоритмах сортировки, поиска кратчайших путей и управления памятью.

История

Понятие кучи как структуры данных было впервые формализовано в 1964 году британским учёным в области информатики Тони Хоаром, который также известен как создатель алгоритма быстрой сортировки. Однако своё современное название и широкое распространение куча получила благодаря работе Роберта Флойда и Джона Уильямса, которые в 1964 году разработали алгоритм пирамидальной сортировки (heapsort). Именно Уильямс ввёл термин «heap» (куча) для описания этой структуры. В последующие десятилетия кучи стали одним из базовых элементов теории алгоритмов и структур данных, изучаемых в курсах информатики во всём мире.

Классификация

Кучи классифицируют по нескольким признакам, основным из которых является тип упорядочения элементов.

По типу упорядочения

По структуре дерева

Устройство и характеристики

Основная идея кучи заключается в поддержании частичного порядка среди элементов. В отличие от полностью упорядоченных структур, таких как двоичное дерево поиска, куча гарантирует только то, что корень содержит экстремальный элемент (максимальный или минимальный). Это позволяет выполнять операции вставки и извлечения экстремума за логарифмическое время.

Операции

Над кучей определены следующие основные операции:

Реализация на массиве

Двоичная куча часто реализуется с помощью массива, что позволяет эффективно использовать кэш-память процессора. Для элемента с индексом i (индексация обычно начинается с 0 или 1) его потомки находятся по индексам 2i+1 и 2i+2 (при индексации с 0), а родитель — по индексу (i-1)/2 (целочисленное деление).

Применение

Кучи являются фундаментальной структурой данных, нашедшей применение в самых разных областях программирования и вычислительной техники.

Пирамидальная сортировка (Heapsort)

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

Приоритетные очереди

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

Алгоритмы на графах

Управление памятью

В системах программирования термин «куча» (heap) также используется для обозначения области динамической памяти, из которой выделяются блоки для объектов и структур данных. Хотя эта область не обязательно реализована как структура данных «куча», её название исторически связано с тем, что выделение и освобождение памяти в ней часто управляется с помощью приоритетных очередей или структур, напоминающих кучу. В частности, сборщики мусора в языках программирования (например, Java, C#) могут использовать кучи для отслеживания доступных блоков памяти.

Медианная фильтрация

В обработке сигналов и изображений кучи используются для реализации медианных фильтров, которые позволяют удалять шум, сохраняя края объектов. Фильтр скользящего окна может быть эффективно реализован с помощью двух куч (макс-кучи и мин-кучи), поддерживающих текущую медиану.

Примеры

Пример на псевдокоде (макс-куча)

``` // Вставка элемента function insert(heap, value): heap.append(value) i = heap.length - 1 while i > 0 and heap[parent(i)] < heap[i]: swap(heap[parent(i)], heap[i]) i = parent(i)

// Извлечение максимума function extractMax(heap): max = heap[0] heap[0] = heap[heap.length - 1] heap.pop() siftDown(heap, 0) return max

// Процедура опускания function siftDown(heap, i): largest = i left = 2i + 1 right = 2i + 2 if left < heap.length and heap[left] > heap[largest]: largest = left if right < heap.length and heap[right] > heap[largest]: largest = right if largest != i: swap(heap[i], heap[largest]) siftDown(heap, largest) ```

Интересные факты

Критика

Несмотря на свою эффективность, кучи имеют ряд ограничений. Основным недостатком является невозможность быстрого поиска произвольного элемента. Если требуется найти элемент по значению, а не по приоритету, куча не предоставляет эффективных средств для этого (поиск занимает O(n)). Кроме того, двоичные кучи не поддерживают эффективное слияние, что ограничивает их применение в задачах, где требуется объединение нескольких приоритетных очередей. Для таких случаев разработаны более сложные структуры, такие как биномиальные кучи и кучи Фибоначчи.

Источники

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →