当前位置: 首页 > news >正文

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;
}

输出结果为:

相关文章:

  • 探索元生代:ComfyUI 工作流与计算机视觉的奇妙邂逅
  • 【数据结构】第四弹——LinkedList与链表
  • chili3d调试笔记3 加入c++ 大模型对话方法 cmakelists精读
  • 学习海康VisionMaster之中线查找
  • 力扣每日打卡 2176. 统计数组中相等且可以被整除的数对(简单)
  • Docker使用、容器迁移
  • Vue实现版本检测与升级
  • 软件开发中的入静与禅定:探寻深度专注与灵感的源泉
  • 【人力资源管理系统】C#实现
  • Linux之基础命令
  • 笔记整理四
  • Java基础 4.18
  • ctfshow-大赛原题-web702
  • 基于WOA鲸鱼优化的NARMAX模型参数辨识算法MATLAB仿真,对比PSO优化算法
  • 云计算(Cloud Computing)概述——从AWS开始
  • 守护进程编程
  • 音视频之H.265/HEVC变换编码
  • kafka jdbc connector适配kadb数据实时同步
  • Uniapp调用native.js使用经典蓝牙串口通讯方法及问题解决
  • Web 前端包管理工具深度解析:npm、yarn、pnpm 全面对比与实战建议
  • 凝聚多方力量,中国农科院油菜产业专家团部署单产提升新任务
  • 建投读书会·东西汇流|全球物品:跨文化交流视域下的明清外销瓷
  • 政治局会议深度|提出“设立新型政策性金融工具”有何深意?
  • 明查|把太平洋垃圾污染问题甩锅中国,特朗普用的是P过的图
  • 四川公布一起影视盗版案例:1个网站2人团伙盗售30多万部
  • 贵州赤水被指“整改复耕”存形式主义,当地部署耕地流出整改“回头看”