Очередь с приоритетами¶
Очередь с приоритетами — это абстрактный тип данных (ADT) в информатике, представляющий собой коллекцию элементов, каждый из которых имеет связанный с ним приоритет. В отличие от обычной очереди (FIFO, «первым пришёл — первым вышел»), извлечение элемента из очереди с приоритетами всегда происходит по наибольшему (или наименьшему) приоритету, независимо от порядка добавления. Элемент с наивысшим приоритетом всегда обслуживается первым. Если несколько элементов имеют одинаковый приоритет, порядок их обслуживания может быть произвольным или определяться дополнительными правилами (например, порядком поступления).
¶Основные операции
Очередь с приоритетами поддерживает три базовые операции:
- Insert (или push, enqueue) — добавление нового элемента с заданным приоритетом.
- Extract-Max (или Extract-Min, pop, dequeue) — удаление и возврат элемента с наибольшим (или наименьшим) приоритетом.
- Peek (или Find-Max, Find-Min, top) — получение элемента с наибольшим (или наименьшим) приоритетом без его удаления.
Дополнительно могут поддерживаться операции изменения приоритета элемента (decrease-key, increase-key), удаления произвольного элемента, слияния двух очередей.
¶Реализации
Очередь с приоритетами может быть реализована различными структурами данных, выбор которых зависит от требуемой производительности операций и ограничений по памяти.
¶Неупорядоченный список (массив)
Простейшая реализация: элементы хранятся в списке или массиве без какой-либо сортировки. Операция Insert выполняется за O(1) (добавление в конец), а Extract-Max требует линейного просмотра всех элементов для поиска максимума — O(n). Реализация неэффективна для частых извлечений.
¶Упорядоченный список (массив)
Элементы хранятся в отсортированном по убыванию (или возрастанию) приоритета порядке. Операция Extract-Max выполняется за O(1) (удаление первого элемента), но Insert требует поиска позиции для вставки и сдвига элементов — O(n). Применима, когда число вставок невелико.
¶Бинарная куча (куча)
Наиболее распространённая и эффективная реализация. Бинарная куча — это полное бинарное дерево, удовлетворяющее свойству кучи: для max-кучи приоритет любого узла не меньше приоритетов его потомков. Реализуется на основе массива. Операции Insert и Extract-Max выполняются за O(log n). Peek — за O(1). Бинарная куча является основой для многих алгоритмов (например, пирамидальной сортировки, алгоритма Дейкстры).
¶Биномиальная куча
Биномиальная куча — это набор биномиальных деревьев, каждое из которых удовлетворяет свойству кучи. Поддерживает эффективное слияние двух очередей (merge) за O(log n). Операции Insert и Extract-Max также выполняются за O(log n). Используется в алгоритмах, где требуется частое объединение очередей.
¶Фибоначчиева куча
Фибоначчиева куча — более сложная структура, обеспечивающая амортизированное время O(1) для операций Insert, Decrease-Key и Merge, и O(log n) для Extract-Max. Применяется в алгоритмах, где критично большое количество операций изменения приоритета (например, в алгоритме Дейкстры с большими графами).
¶Двоичная куча (d-арная куча)
Обобщение бинарной кучи, где каждый узел имеет до d потомков. Увеличение d уменьшает высоту дерева (ускоряет Extract-Max), но замедляет Insert из-за большего числа сравнений при просеивании. Параметр d выбирается в зависимости от соотношения операций.
¶Очередь с приоритетами на основе дерева поиска
Сбалансированные деревья поиска (например, красно-чёрные деревья, AVL-деревья) также могут быть использованы для реализации очереди с приоритетами. Операции вставки, удаления и поиска максимума выполняются за O(log n). Однако такая реализация избыточна по сравнению с кучей, так как требует поддержания полной упорядоченности, что не нужно для очереди с приоритетами.
¶Применение
Очередь с приоритетами широко используется в различных областях информатики и программирования:
- Алгоритмы на графах: алгоритм Дейкстры (поиск кратчайших путей), алгоритм Прима (построение минимального остовного дерева), алгоритм A* (поиск пути с эвристикой).
- Операционные системы: планирование процессов (выбор процесса с наивысшим приоритетом для выполнения), управление прерываниями.
- Сетевые технологии: маршрутизация пакетов с приоритетами (Quality of Service, QoS), управление очередями в коммутаторах и маршрутизаторах.
- Сжатие данных: алгоритм Хаффмана (построение оптимального префиксного кода) использует очередь с приоритетами для выбора двух узлов с наименьшими частотами.
- Дискретная оптимизация: алгоритмы ветвей и границ, поиск в пространстве состояний.
- Симуляция событий: в дискретно-событийной симуляции очередь с приоритетами используется для хранения событий, упорядоченных по времени их наступления.
- Обработка данных: в системах реального времени (например, в играх) для обработки объектов с разными приоритетами обновления.
¶Разновидности
¶Max-очередь и Min-очередь
В зависимости от того, какой элемент извлекается первым, различают:
- Max-очередь с приоритетами (max-priority queue) — извлекается элемент с наибольшим приоритетом.
- Min-очередь с приоритетами (min-priority queue) — извлекается элемент с наименьшим приоритетом.
Любая max-очередь может быть преобразована в min-очередь путём инвертирования приоритетов (например, умножением на -1).
¶Двусторонняя очередь с приоритетами
Позволяет извлекать как максимальный, так и минимальный элемент. Реализуется, например, с помощью двух куч (min-куча и max-куча) или с помощью декартова дерева.
¶Очередь с приоритетами с изменяемым приоритетом
Поддерживает операцию изменения приоритета уже добавленного элемента (decrease-key или increase-key). Это необходимо, например, в алгоритме Дейкстры, где приоритет вершины может уменьшаться. Фибоначчиевы кучи оптимизированы под эту операцию.
¶История
Понятие очереди с приоритетами как абстрактного типа данных было формализовано в 1960-х годах. Бинарная куча была впервые описана Дж. Уильямсом в 1964 году в контексте алгоритма пирамидальной сортировки (heapsort). Биномиальные кучи были предложены Жаном Вюйлеменом в 1978 году. Фибоначчиевы кучи разработаны Майклом Фредманом и Робертом Тарьяном в 1984 году. Дальнейшие исследования привели к созданию множества других структур, таких как кучи Бродаля, тонкие кучи, ранговые кучи.
¶Интересные факты
- В стандартной библиотеке языка C++ очередь с приоритетами реализована в виде шаблонного класса
std::priority_queue, который по умолчанию используетstd::vectorи бинарную кучу (max-кучу). - В Java существует класс
PriorityQueue(min-куча), а такжеPriorityBlockingQueueдля многопоточных приложений. - В Python очередь с приоритетами реализована в модуле
heapq(min-куча). Для max-кучи используется инвертирование приоритетов. - В .NET (C#) очередь с приоритетами появилась в .NET 6 (2021 год) в виде класса
PriorityQueue<TElement, TPriority>. - В языке Go очередь с приоритетами не встроена в стандартную библиотеку, но её можно реализовать с помощью интерфейса
heap.Interface.
¶Источники
- Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein. Introduction to Algorithms (3rd ed.). MIT Press, 2009.
- Donald E. Knuth. The Art of Computer Programming, Volume 3: Sorting and Searching (2nd ed.). Addison-Wesley, 1998.
- Michael L. Fredman, Robert E. Tarjan. Fibonacci heaps and their uses in improved network optimization algorithms. Journal of the ACM, 1987.
- Jean Vuillemin. A data structure for manipulating priority queues. Communications of the ACM, 1978.
- J. W. J. Williams. Algorithm 232: Heapsort. Communications of the ACM, 1964.
- Документация стандартной библиотеки C++ (cppreference.com).
- Документация Python (docs.python.org).
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


