STL详解 - priority_queue
目录
一、priority_queue 是什么
二、priority_queue 的底层实现
三、priority_queue 的定义方式
四、priority_queue 的成员函数
五、priority_queue 使用示例
六、priority_queue 的自定义比较方式
七、priority_queue 的模拟实现
一、priority_queue
是什么
priority_queue
是一种容器适配器,它的核心特性是:队列中第一个元素始终是队列中最大的元素(默认情况下)。这使得priority_queue
在处理需要按照优先级排序的数据时非常高效。- 例如,在任务调度系统中,优先级高的任务应该先被执行;在模拟场景中,事件按照时间顺序处理。这些场景都可以通过
priority_queue
来实现。
二、priority_queue
的底层实现
priority_queue
默认使用 vector
作为底层存储容器,并通过堆算法将元素组织成堆结构。堆是一种特殊的树状结构,分为大顶堆和小顶堆:
-
大顶堆 :父节点的值大于或等于子节点的值,
priority_queue
默认构造的是大顶堆。 -
小顶堆 :父节点的值小于或等于子节点的值。
三、priority_queue
的定义方式
1. 使用 vector 作为底层容器,构造大顶堆
priority_queue<int, vector<int>, less<int>> q1;
- 这里明确指定了底层容器为
vector
,比较方式为less<int>
,即元素按照从小到大的顺序比较,构造出大顶堆。
2. 使用 vector 作为底层容器,构造小顶堆
priority_queue<int, vector<int>, greater<int>> q2;
- 此时比较方式为
greater<int>
,元素按照从大到小的顺序比较,构造出小顶堆。
3. 默认定义
priority_queue<int> q3;
- 这是最简洁的定义方式。此时底层容器默认为
vector
,比较方式默认为less<int>
,即构造大顶堆。
四、priority_queue
的成员函数
方法 | 功能描述 | 时间复杂度 |
---|---|---|
push(x) | 插入元素并重新排序 | O(logN) |
pop() | 删除堆顶元素 | O(logN) |
top() | 访问堆顶元素 | O(1) |
empty() | 判断队列是否为空 | O(1) |
size() | 获取元素数量 | O(1) |
1. push
:插入元素
将元素插入到 priority_queue
中,并自动调整堆结构以维护优先级关系。
q.push(10);
q.push(5);
q.push(15);
插入元素后,堆会自动调整,大顶堆的堆顶始终是最大元素。
2. pop
:删除堆顶元素
移除 priority_queue
中的最大元素(大顶堆)或最小元素(小顶堆),并调整堆结构。
q.pop();
执行 pop
操作后,堆顶元素被删除,堆结构重新调整以维护优先级关系。
3. top
:访问堆顶元素
返回 priority_queue
中的最大元素(大顶堆)或最小元素(小顶堆),但不删除该元素。
int maxElement = q.top(); // 对于大顶堆,获取最大元素
4. size
:获取队列中元素个数
返回 priority_queue
中当前有效的元素数量。
size_t count = q.size();
5. empty
:判断队列是否为空
检测 priority_queue
是否为空,若为空返回 true
,否则返回 false
。
if (q.empty())
{cout << "队列为空" << endl;
}
else
{cout << "队列不为空" << endl;
}
6. swap
:交换两个队列的内容
交换两个 priority_queue
的元素内容。
priority_queue<int> q1, q2;// ... 向 q1 和 q2 中添加元素 ...q1.swap(q2);
五、priority_queue
使用示例
#include <iostream>
#include <queue>
using namespace std;int main()
{priority_queue<int> q;// 向队列中添加元素q.push(3);q.push(1);q.push(4);q.push(2);q.push(5);// 输出队列中的元素cout << "队列中的元素按优先级顺序排列:" << endl;while (!q.empty()) {cout << q.top() << " "; // 输出堆顶元素q.pop(); // 删除堆顶元素}cout << endl;return 0;
}
从输出结果可以看出,元素按照从大到小的顺序输出,符合大顶堆的特点。
六、priority_queue
的自定义比较方式
除了使用默认的大顶堆和小顶堆,我们还可以自定义比较方式,以满足特定的需求。
例如,假设我们有一个 Student
类,我们希望按照学生的成绩来构造 priority_queue:
#include <iostream>
#include <queue>
#include <string>
using namespace std;class Student
{
public:string name;int score;Student(string n, int s) : name(n), score(s) {}// 重载 < 运算符,用于比较两个学生对象bool operator<(const Student& other) const {return score < other.score; // 按成绩从高到低排序}
};int main()
{priority_queue<Student> students;students.push(Student("Alice", 90));students.push(Student("Bob", 80));students.push(Student("Charlie", 95));// 输出学生信息,按成绩从高到低排列cout << "学生按成绩从高到低排列:" << endl;while (!students.empty()) {cout << students.top().name << ": " << students.top().score << endl;students.pop();}return 0;
}
在这个例子中,我们通过重载 Student
类的 <
运算符,自定义了比较方式,使得 priority_queue
按照学生的成绩从高到低排序。
七、priority_queue
的模拟实现
#pragma once#include <iostream>
#include <vector>
using namespace std;namespace lv // 防止命名冲突
{// 大顶堆比较器(默认)template<class T>struct less {bool operator()(const T& x, const T& y) const {return x < y; // 父节点小于子节点时交换}};// 小顶堆比较器template<class T>struct greater {bool operator()(const T& x, const T& y) const {return x > y; // 父节点大于子节点时交换}};// 优先级队列模板类template<class T, class Container = std::vector<T>, class Compare = less<T>>class priority_queue{public:// 默认构造函数priority_queue() = default;// 通过迭代器范围构造template <class InputIterator>priority_queue(InputIterator first, InputIterator last, const Compare& comp = Compare()): _con(first, last), _comp(comp){// 从最后一个非叶子节点开始建堆for (int i = (_con.size() - 1) / 2; i >= 0; --i) {AdjustDown(_con.size(), i);}}// 插入元素void push(const T& x) {_con.push_back(x); // 插入尾部AdjustUp(_con.size() - 1); // 向上调整}// 删除堆顶void pop() {if (empty()) return; // 空队列处理std::swap(_con[0], _con.back()); // 交换首尾_con.pop_back(); // 删除尾部AdjustDown(_con.size(), 0); // 向下调整}// 访问堆顶T& top() { return _con.front(); }const T& top() const {return _con.front(); }// 容量操作size_t size() const {return _con.size(); }bool empty() const {return _con.empty(); }private:Container _con; // 底层容器Compare _comp; // 比较器// 向上调整(插入时使用)void AdjustUp(int child) {while (child > 0) {int parent = (child - 1) / 2;if (_comp(_con[parent], _con[child])) { // 比较父子节点std::swap(_con[parent], _con[child]);child = parent;}else {break; // 堆结构已满足}}}// 向下调整(删除时使用)void AdjustDown(int heapSize, int parent) {int child = 2 * parent + 1; // 左子节点while (child < heapSize) {// 选择更大的子节点if (child + 1 < heapSize && _comp(_con[child], _con[child + 1])) {++child;}// 比较父子节点if (_comp(_con[parent], _con[child])) {std::swap(_con[parent], _con[child]);parent = child;child = 2 * parent + 1;}else {break; // 堆结构已满足}}}};
}
测试代码:
// 测试代码
#include "priority_queue.h"int main()
{lv::priority_queue<int> pq;pq.push(10);pq.push(5);pq.push(15);pq.push(7);pq.push(20);cout << "priority_queue elements (top to bottom):" << endl;while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;// 测试小顶堆lv::priority_queue<int, vector<int>, greater<int>> min_pq;min_pq.push(10);min_pq.push(5);min_pq.push(15);min_pq.push(7);min_pq.push(20);cout << "min_pq elements (top to bottom):" << endl;while (!min_pq.empty()){cout << min_pq.top() << " ";min_pq.pop();}cout << endl;return 0;
}
输出结果为: