Объяснение
Очередь с приоритетом — это структура данных, где первым выходит не тот, кто раньше зашел, а тот, у кого приоритет выше.
кто первый пришел → тот первый вышел
очередь с приоритетом:
у кого приоритет больше → тот первый вышел
В C++ для этого есть готовая структура:
priority_queue<int> q;
Внутри priority_queue обычно работает через binary heap. То есть это удобная готовая куча.
Главные операции
| Операция | Что делает | Время |
|---|---|---|
| push(x) | добавляет элемент x | O(log n) |
| top() | возвращает элемент с самым высоким приоритетом | O(1) |
| pop() | удаляет верхний элемент | O(log n) |
| size() | возвращает размер очереди | O(1) |
| empty() | проверяет, пустая очередь или нет | O(1) |
Max-heap
По умолчанию priority_queue<int> работает как max-heap. Самое большое число всегда находится сверху.
priority_queue<int> q;
q.push(5);
q.push(2);
q.push(7);
cout << q.top();
Ответ будет:
7
самый большой элемент = 7
q.top() = 7
Маленький пример с pop
priority_queue<int> q;
q.push(5);
q.push(2);
q.push(7);
cout << q.top() << '\n';
q.pop();
cout << q.top() << '\n';
Вывод:
7
5
Сначала наверху было 7. После pop() число 7 удалилось, и наверху стало 5.
Min-heap
Чтобы сверху был самый маленький элемент, нужно написать так:
priority_queue<int, vector<int>, greater<int>> q;
Это уже min-heap.
priority_queue<int, vector<int>, greater<int>> q;
q.push(5);
q.push(2);
q.push(7);
cout << q.top();
Ответ будет:
2
самый маленький элемент = 2
q.top() = 2
Пример задачи 1: обычная очередь с приоритетом
Нужно обработать команды для min-heap.
| Команда | Что делает |
|---|---|
| push x | добавить число x |
| top | вывести минимальный элемент |
| pop | удалить минимальный элемент |
| size | вывести размер очереди |
Input
9
push 5
push 2
push 7
top
pop
top
push 1
top
size
Output
2
5
1
3
Полная реализация min-heap
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
priority_queue<int, vector<int>, greater<int>> q;
int n;
cin >> n;
while (n--) {
string op;
cin >> op;
if (op == "push") {
int x;
cin >> x;
q.push(x);
} else if (op == "top") {
cout << q.top() << '\n';
} else if (op == "pop") {
q.pop();
} else if (op == "size") {
cout << q.size() << '\n';
}
}
return 0;
}
Очередь с приоритетом для pair
Часто в задачах нужно хранить не одно число, а пару. Например:
Для этого можно использовать:
priority_queue<pair<int, int>> q;
По умолчанию пары сравниваются так:
- сначала сравнивается first
- если first одинаковые, сравнивается second
Пример max-heap для pair
priority_queue<pair<int, int>> q;
q.push({5, 1});
q.push({10, 2});
q.push({7, 3});
cout << q.top().first << ' ' << q.top().second;
Ответ:
10 2
самый большой first = 10
top = {10, 2}
Min-heap для pair
Чтобы получить минимальную пару, пишем:
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
Пример
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
q.push({5, 1});
q.push({10, 2});
q.push({7, 3});
cout << q.top().first << ' ' << q.top().second;
Ответ:
5 1
Пример задачи 2: обработка задач по важности
Пусть есть задачи. У каждой задачи есть:
- priority — важность
- id — номер задачи
Нужно всегда брать задачу с максимальной важностью.
Input
7
add 10 1
add 5 2
add 20 3
top
pop
top
size
Output
20 3
10 1
2
Реализация с pair
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
priority_queue<pair<int, int>> q;
int n;
cin >> n;
while (n--) {
string op;
cin >> op;
if (op == "add") {
int priority, id;
cin >> priority >> id;
q.push({priority, id});
} else if (op == "top") {
cout << q.top().first << ' ' << q.top().second << '\n';
} else if (op == "pop") {
q.pop();
} else if (op == "size") {
cout << q.size() << '\n';
}
}
return 0;
}
Как это работает?
add 5 2 → задача с priority 5 и id 2
add 20 3 → задача с priority 20 и id 3
Так как это max-heap, наверху будет задача с самым большим priority.
Своя сортировка
Иногда нужно задать свои правила сравнения. Тогда можно написать структуру cmp.
Например, хотим, чтобы сверху была задача с меньшим временем.
struct Task {
int time;
int id;
};
struct cmp {
bool operator()(Task a, Task b) {
return a.time > b.time;
}
};
priority_queue<Task, vector<Task>, cmp> q;
Здесь сверху будет задача с минимальным time.
Полный маленький пример
#include <bits/stdc++.h>
using namespace std;
struct Task {
int time;
int id;
};
struct cmp {
bool operator()(Task a, Task b) {
return a.time > b.time;
}
};
int main() {
priority_queue<Task, vector<Task>, cmp> q;
q.push({10, 1});
q.push({5, 2});
q.push({20, 3});
cout << q.top().time << ' ' << q.top().id;
return 0;
}
Ответ:
5 2
Где используется priority_queue?
- Алгоритм Дейкстры
- Жадные алгоритмы
- Задачи с расписанием
- Симуляции событий
- Нахождение k самых больших или маленьких элементов
Асимптотика
| Операция | Время |
|---|---|
| push | O(log n) |
| pop | O(log n) |
| top | O(1) |
| size | O(1) |
| empty | O(1) |