在 C++ STL(标准模板库)中,priority_queue
是 优先队列,它是一种特殊的队列,出队顺序 按照优先级排序,而非 FIFO(先进先出)。底层实现通常基于 堆(heap) 数据结构,因此具有 高效的插入和删除操作。
1. priority_queue
的基本特点
-
按优先级出队:默认情况下,元素按 大顶堆(最大值优先) 方式存储。
与普通的队列(queue
)不同,priority_queue
中的元素并不是按照先进先出(FIFO)的顺序进行处理,而是按照优先级的高低进行处理。默认情况下,priority_queue
是一个最大堆,即优先级最高的元素(通常是最大的元素)会最先被取出。 -
底层结构:基于 堆(heap),通常是 二叉堆。
-
时间复杂度:插入和删除的时间复杂度均为
O(log n)
。
2. priority_queue
的基本用法
2.1 priority_queue
的定义与初始化
priority_queue<T, Container, Compare> pq;//T:存储的元素类型。
//Container:底层容器类型,默认为vector<T>。
//Compare:比较函数对象类型,默认为less<T>,即最大堆。
定义一个存储整数的最大堆:
priority_queue<int> maxHeap;定义一个存储整数的最小堆:
priority_queue<int, vector<int>, greater<int>> minHeap;
#include <iostream>
#include <queue>
using namespace std;int main() {priority_queue<int> pq;// 插入元素pq.push(10);pq.push(30);pq.push(20);// 访问队头(最大值)cout << "队头: " << pq.top() << endl;return 0;
}
输出:
队头: 30
可以看到,最大元素优先出队。
2.2 插入与删除
pq.push(40); // 插入 40
pq.pop(); // 移除最大值(40)
2.3 访问队头元素(顶部元素)
使用top()
方法访问priority_queue
中的顶部元素(即优先级最高的元素):
cout << "队头: " << pq.top() << endl;
2.4 检查队列是否为空
if (pq.empty()) {cout << "队列为空" << endl;
}
2.5 获取队列大小
cout << "队列大小: " << pq.size() << endl;
3. priority_queue
的自定义排序
最小值优先
默认情况下,priority_queue
是 大顶堆,如果需要 小顶堆(最小值优先),可以使用 greater<>
:
priority_queue<int, vector<int>, greater<int>> minHeap;
如果需要 自定义排序规则,可以使用结构体或 Lambda 表达式:
struct Compare {bool operator()(int a, int b) {return a > b; // 小值优先}
};
priority_queue<int, vector<int>, Compare> customPQ;
结构体排序示例
如果 priority_queue
需要存储 自定义结构体(如商品、任务等),可以重载 operator<
进行排序。例如:晴问算法--priority_queue-结构体
#include <bits/stdc++.h>
using namespace std;struct Fruit {string name;int price;Fruit(string _name, int _price) { //构造函数name = _name;price = _price;}bool operator<(const Fruit& other) const {return price > other.price; // 价格低的优先出队}
};int main() {priority_queue<Fruit> q;int n;cin >> n;while (n--) {string name;int price;cin >> name >> price;q.push(Fruit(name, price));//将Fruit对象推入优先队列q中}Fruit topFruit = q.top();cout << topFruit.name << " " << topFruit.price;return 0;
}
在这道题目中,我们需要实现一个优先队列来存储不同水果的信息,并根据价格进行排序。具体来说,我们需要定义一个结构体
Fruit
,并在其中重载<
操作符,以便优先队列能够根据价格进行排序。最后,我们需要将水果信息输入到优先队列中,并输出队首水果的名称和价格。
补充:结构体与构造函数
1. 结构体
结构体可以将多个相同或不同类型的变量组合在一起,语法如下:
struct Point {int x, y; };
通过上面的写法可以将两个 int 型变量 x 和 y 组合成一个复合类型。对
C++
来说,Point
就是这个新的复合类型,我们在之后的代码中可以直接使用Point
来指代这个类型。但是对
C
语言来说,struct Point
才是新的复合类型,因此在之后的代码中必须使用struct Point
来指代这个类型。不过这确实有些麻烦,所以常见的做法是在定义结构体之后额外增加一条typedef
语句,将struct Point
类型用别名Point
代替,这样后续代码就可以直接使用Point
来指代这个结构体类型,会简单许多,示例如下(注意只有C
语言才需要):C
struct Point {int x, y; }; typedef struct Point Point;
当然我们也可以将上面的两个定义合在一起:
C
typedef struct Point {int x, y; } Point;
上面这个结构看起来复杂,但其实就是
typdef struct Point {...} Point
的意思,也就是说给结构体类型struct Point {...}
取了个类型别名Point
,这样后续代码就可以直接使用Point
这个名字了。2. 构造函数
构造函数是在结构体内部定义的一种特殊函数,可以用来构造结构体变量,它的 函数名和结构体名相同,并且 没有返回类型。
本题要求构造函数接收两个参数,并把这两个参数分别赋值给结构体内的两个变量,以此来生成一个带有初始值的结构体变量。
下面是题目要求使用的构造函数(函数的参数名使用下划线(例如
_x
)只是为了和结构体内部定义的变量(例如x
)区分,也可以叫其他名字):C++
Point(int _x, int _y) {x = _x;y = _y; }
它也可以简写为:
C++
Point(int _x, int _y): x(_x), y(_y) {}
在定义了上面的构造函数之后,我们就可以使用
Point(1, 2)
这种方式来构造带初始值的结构体变量。而如果不写构造函数的话,默认会生成一个构造函数,这个构造函数没有参数,并且不对结构体内的变量赋初值,这个构造函数是这样的:
C++
Point() {}
这个默认构造函数的作用是定义未被赋初值的结构体变量,例如:
C++
Point p; Point ps[100];
需要注意,一旦我们自己定义了一个构造函数,就会把上面这个默认构造函数覆盖掉,此时只定义结构体变量而不对其赋初值时不允许的。解决办法也很简单,手动将这个默认构造函数补上即可,因为 一个结构体内是允许同时存在多个构造函数的。
输入示例:
3
Apple 50
Banana 30
Cherry 40
输出:
Banana 30
此代码实现了一个 按价格排序的优先队列,其中 价格最低的水果最先出队。
4. priority_queue
的应用场景
-
任务调度:优先级最高的任务最先处理。
-
Dijkstra 最短路径算法:用于维护最短路径的候选点。
-
Huffman 编码:构造最优前缀编码树。
5. priority_queue
与 queue
、set
的区别
特性 | priority_queue | queue | set |
---|---|---|---|
底层结构 | 堆(heap) | 双端队列(deque) | 红黑树(BST) |
元素顺序 | 按优先级出队 | 先进先出(FIFO) | 按 key 排序 |
插入/删除复杂度 | O(log n) | O(1) | O(log n) |
适用场景 | 任务调度、最短路径 | 普通队列 | 去重、有序存储 |
总结
priority_queue
是 C++ STL 中的 优先队列,适用于 任务调度、最短路径和 Huffman 编码 等场景。默认是 大顶堆,可通过 greater<>
实现 小顶堆,也可以自定义排序规则。