PriorityQueue в PascalABC.NET: очередь с приоритетами в .NET 10
Версия компилятора PascalABC.NET для .NET 10 позволяет напрямую использовать классы современной стандартной библиотеки .NET. Один из полезных примеров — PriorityQueue<TElement,TPriority> из пространства имён System.Collections.Generic.
Что такое очередь с приоритетами
Обычная очередь работает по принципу «первым пришёл — первым вышел». В очереди с приоритетами порядок извлечения определяется не временем добавления, а приоритетом элемента.
Рассмотрим очередь задач. Договоримся, что меньшее число означает более срочную задачу:
uses System.Collections.Generic;
begin
var tasks := new PriorityQueue<string,integer>;
tasks.Enqueue('Создать резервную копию',3);
tasks.Enqueue('Обработать срочный запрос',1);
tasks.Enqueue('Сформировать отчёт',2);
while tasks.Count > 0 do
Println(tasks.Dequeue);
end.
Результат:
Обработать срочный запрос
Сформировать отчёт
Создать резервную копию
Тип элемента и тип приоритета
В объявлении
PriorityQueue<string,integer>
string задаёт тип элементов очереди, а integer — тип их приоритетов. Элементы и приоритеты могут иметь и другие типы, если они подходят решаемой задаче.
Метод Enqueue добавляет элемент вместе с его приоритетом:
tasks.Enqueue('Обработать срочный запрос',1);
При вызове Dequeue извлекается элемент с наименьшим значением приоритета. Поэтому сначала выводится срочный запрос с приоритетом 1, затем формирование отчёта с приоритетом 2 и только потом создание резервной копии с приоритетом 3, хотя оно было добавлено первым.
Название задачи никак не влияет на порядок: очередь сравнивает только значения приоритетов.
Зачем нужна очередь задач
В работающей системе задачи могут поступать быстрее, чем их удаётся выполнять. Например, сервис получает запросы пользователей и одновременно готовит отчёты и резервные копии. Если обрабатывать всё в порядке поступления, срочный запрос будет ждать за менее важными задачами.
Очередь с приоритетами позволяет выбрать самую срочную из ожидающих задач, когда исполнитель освобождается. Новая срочная задача может быть добавлена позже остальных, но извлечена раньше них. Это полезно, например, при распределении обращений в службу поддержки или выборе фоновых заданий для обработки.
При этом PriorityQueue сама не выполняет задачи и не прерывает уже начатую работу — она только хранит элементы и определяет, какой из них извлечь следующим. В нашем примере задачи представлены названиями, поэтому программа лишь выводит их в выбранном порядке. В реальной программе после извлечения запускалась бы соответствующая операция.
Если срочные задачи поступают постоянно, менее важные могут долго оставаться в очереди. Поэтому в реальных системах иногда дополнительно учитывают время ожидания, а не только исходную срочность.
Основные операции PriorityQueue
Enqueue(element, priority)добавляет элемент с заданным приоритетом;Dequeueудаляет и возвращает элемент с наименьшим приоритетом;Peekвозвращает следующий элемент, не удаляя его;Countсодержит текущее количество элементов;TryDequeueпозволяет безопасно попытаться извлечь элемент и его приоритет.
Если несколько элементов имеют одинаковый приоритет, PriorityQueue не гарантирует для них порядок «первым добавлен — первым извлечён». Если такой порядок важен, его следует задать дополнительно, например включив номер добавления в значение приоритета.
Где применяется очередь с приоритетами
Очереди с приоритетами используются:
- при поиске кратчайших путей в графах, например в алгоритме Дейкстры;
- при планировании задач;
- в моделировании событий;
- при обработке запросов разной важности;
- во многих других алгоритмах, где каждый следующий элемент выбирается по приоритету.
Классический пример — алгоритм Дейкстры. В статье «Алгоритм Дейкстры в PascalABC.NET» разобрана полная программа поиска кратчайших расстояний в графе с помощью PriorityQueue.
PriorityQueue — ещё один пример того, как PascalABC.NET получает прямой доступ к возможностям стандартной библиотеки .NET 10.