目录
一、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;
}
输出结果为:

403

被折叠的 条评论
为什么被折叠?



