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

【C++ STL】 容器详解:priority_queue 学习

在 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_queuequeueset 的区别

特性priority_queuequeueset
底层结构堆(heap)双端队列(deque)红黑树(BST)
元素顺序按优先级出队先进先出(FIFO)按 key 排序
插入/删除复杂度O(log n)O(1)O(log n)
适用场景任务调度、最短路径普通队列去重、有序存储

总结

priority_queue 是 C++ STL 中的 优先队列,适用于 任务调度、最短路径和 Huffman 编码 等场景。默认是 大顶堆,可通过 greater<> 实现 小顶堆,也可以自定义排序规则。

相关文章:

  • 大语言模型学习--向量数据库Milvus实践
  • 【大模型学习】第十六章 模型微调技术综述
  • 【eNSP实战】MSTP与VRRP配合使用
  • 图论part2|200. 岛屿数量、695. 岛屿的最大面积
  • 如何制作Windows系统盘、启动盘?(MediaCreationTool_22H2)
  • 韦伯望远镜的拉格朗日点计算推导过程,包含MATLAB和python运动轨迹仿真代码
  • Redis 数据持久化之AOF
  • 3-2 深入解析数字电路设计中的竞争条件及解决策略
  • blazemeter工具使用--用于自动生成jmeter脚本并进行性能测试
  • 【动手学深度学习】基于SoftMax回归算法实现图片分类
  • docker-compose部署MongoDB分片集群
  • 如何绕过 reCAPTCHA V2/V3:Python、Selenium 与其他工具的实战指南
  • Unity 封装一个依赖于MonoBehaviour的计时器(上) 基本功能
  • 30天学习Java第三天——控制循环
  • 电机控制常见面试问题(九)
  • 深度学习 常见优化器
  • ROS实践(四)机器人SLAM建图(gmapping)
  • linux纯干货
  • 汉得 x 头部大型传媒集团|AI革新:智启出版新征程!
  • scoop退回软件版本的方法
  • 游客曝九寨沟打网约车被出租车围堵,官方:前者违规,后者做法不对
  • 总书记考察的上海“模速空间”,是一个怎样的空间?
  • 直播电商行业代表呼吁:携手并肩伸出援手助力外贸企业攻坚克难
  • 湖南华容县通报“大垱湖水质受污染”,爆料者:现场已在灌清水
  • 专访丨青年作家杜梨:以动物的视角去观察这个世界
  • 杜前任宁波中院代理院长,卸任宁波海事法院院长