优先队列介绍
priority_queue 是 C++ 标准模板库(STL)中的一个容器适配器,提供了堆数据结构的实现(默认为最大堆)。它在需要高效访问最大/最小元素的场景下非常有用。
如果需要使用小顶堆,可以这样传参
priority_queue<int, vector<int>, greater<int>>
它是默认基于(大顶)堆实现的,例如一颗用数组存储的完全二叉树:

特点总结:
- 采用数组形式存储
- 默认基于最大堆实现
- 适配器容器底层为 vector(使用需要包含
<queue>) - 每次只能访问队列顶部的元素,即优先级最高的元素
- 复杂度:访问 O(1)、插入 O(log n)、删除顶部元素 O(log n)
优先队列的渊源
通过优先队列的容器结构可以看出,它的底层容器是 vector。为什么不取名叫优先维克托呢?
问:为什么底层容器是 vector? 连续内存结构适合堆的随机访问需求,缓存友好,且动态数组支持高效尾部操作。
问:为什么头文件是 queue? 作为容器适配器,优先队列在概念上属于队列的一种,与 queue 共用同一头文件,体现了接口的一致性,比如队列的各种接口刚好吻合它的访问、插入、删除行为:
priority_queue --> "<queue> 头文件" : 声明接口
问:为什么叫优先队列而不是优先维克托? 名称语义分解:
- 优先 (Priority):元素按内在重要性排序,而非插入顺序
- 队列 (Queue):仅允许特定端点访问的操作模型(队尾插入,队首访问)
行为本质:
- 插入操作:
push(),时间复杂度 O(log n) - 访问操作:
top(),总是获取优先级最高的元素 - 删除操作:
pop(),移除当前最高优先级元素
实例化
采用:priority_queue<数据类型> 变量名;
我们可以选择默认初始化:
priority_queue<int> V1;
也可以选择范围初始化:
priority_queue<int> V2(arr, arr+n); //或者用另一个容器去初始化 priority_queue<int> V3(V1.begin(), V1.end());
效果展示:

插入元素
V.push(val);
访问元素
遵循堆的性质,只能访问堆顶元素
V.top();

获取元素个数
V.size();

判断优先队列是否为空
V.empty();
为空返回 true;不为空返回 false

删除堆顶元素
V.pop();

优先队列的模拟实现
类模板
template<class T, class Container = vector<T>> class priority_queue {
public:
//构造可以不写,因为可以直接使用vector
//函数实现
private:
Container x;
};
既然底层是 vector,我们用缺省参数直接实例化出一个 vector 类型的变量就可以作为底层实现了。
插入元素
插入元素调用 vector 的接口就行了,这里由于需要满足优先队列的性质(大顶堆),我们还需要在插入之后使用向上调整,保证堆顶(首元素)是最大的。
插入元素:
//插入数据
void push(const T& data) {
x.push_back(data); //向上调整
shiftUp(size() - 1);
}
向上调整:
//向上调整
void shiftUp(int child) {
//父节点
int parent = (child - 1) / 2;
//如果孩子节点大于父节点,就向上调整交换(根节点可能也需要调整)
while (parent >= 0) {
//只要进入循环,那么节点下标一定是在合法范围
if (x[child] > x[parent]) {
//交换
swap(x[child], x[parent]);
//更新孩子、父节点
child = parent;
parent = (child - 1) / 2;
} else break;
}
}
这样经过向上调整就可以达到下面的效果:


访问元素
访问第一个元素即可(堆顶元素)
//访问元素
T top() {
return x[0];
}
获取元素个数
//计算元素个数
size_t size() {
return x.size();
}
判断优先队列是否为空
//判断是否为空
bool empty() {
return x.empty();
}
删除堆顶元素
这里的删除调用 vector 的尾删即可。 删除的方法:先交换堆顶和尾部元素,再删除,再使用向下调整保证大顶堆的性质。
//删除堆顶元素
void pop() {
shiftDown(size() - 1);
}
向下调整:
//向下调整
void shiftDown(int child) {
//交换堆顶和末尾元素
swap(x[child], x[0]);
//去尾
x.pop_back();
//父子节点
int parent = 0;
child = 2 * parent + 1;
//开始调整(子节点不能超过范围)
while (child < x.size()) {
//如果右节点大于左节点
if (child + 1 < x.size() && x[child] < x[child + 1]) {
child++;
}
//如果父节点小于子节点
if (x[parent] < x[child]) {
swap(x[parent], x[child]);
//更新
parent = child;
child = 2 * parent + 1;
} else break;
}
}
效果展示
void test() {
priority_queue<int> V1;
//插入元素
V1.push(10);
V1.push(15);
V1.push(5);
V1.push(20);
V1.push(0);
V1.push(25);
//元素个数
cout << V1.size() << endl;
//访问堆顶元素
cout << V1.top() << endl;
//出堆顶元素
V1.pop();
//访问堆顶元素
cout << V1.top() << endl;
//判断是否为空
cout << V1.empty() << endl;
}



