【数据结构与算法】优先队列

一、什么是优先队列?

优先队列就是一个会自动排序的队列。

普通队列 vs 优先队列

cpp 复制代码
// 普通队列:先进先出
queue<int> q;
q.push(3);
q.push(1);
q.push(2);
// 取出顺序:3, 1, 2

// 优先队列:按大小排序
priority_queue<int> pq;
pq.push(3);
pq.push(1);
pq.push(2);
// 取出顺序:3, 2, 1(从大到小)

优先队列的基本用法

1. 头文件

cpp 复制代码
#include <queue>

2. 声明方式

cpp 复制代码
// 方式1:最大堆(默认)
priority_queue<int> pq1;  // 最大的元素在顶部

// 方式2:最小堆
priority_queue<int, vector<int>, greater<int>> pq2;  // 最小的元素在顶部

// 方式3:自定义比较
priority_queue<Node*, vector<Node*>, Compare> pq3;  // 按自定义规则排序

三、常用操作

cpp 复制代码
priority_queue<int> pq;

// 添加元素
pq.push(10);
pq.push(5);
pq.push(20);

// 访问顶部元素
int top = pq.top();  // 返回20(最大值)

// 删除顶部元素
pq.pop();  // 删除20

// 判断是否为空
if (pq.empty()) { }

// 获取大小
int size = pq.size();  // 2

四、三种声明方式详解

方式1:最大堆(默认)

cpp 复制代码
priority_queue<int> pq;
// 等价于
priority_queue<int, vector<int>, less<int>> pq;

特点: 最大的元素在顶部

cpp 复制代码
pq.push(3);
pq.push(1);
pq.push(2);
cout << pq.top();  // 输出 3

方式2:最小堆

cpp 复制代码
priority_queue<int, vector<int>, greater<int>> pq;

特点: 最小的元素在顶部

cpp 复制代码
pq.push(3);
pq.push(1);
pq.push(2);
cout << pq.top();  // 输出 1

方式3:自定义类型

cpp 复制代码
struct Node {
    int weight;
    int ascii;
};

struct Compare {
    bool operator()(Node a, Node b) {
        // 返回true表示a的优先级低于b
        if (a.weight != b.weight) {
            return a.weight > b.weight;  // 权值小的优先
        }
        return a.ascii > b.ascii;  // ASCII小的优先
    }
};

priority_queue<Node, vector<Node>, Compare> pq;

优先队列本质上就是一种"每次都能快速取出最大或最小元素"的数据结构,你可以把它理解成一个"自动排序的队列",但它不是完全排序的,而是始终保证队头元素是当前优先级最高的那个;在 C++ 里,默认是大根堆,也就是每次取出最大值。

先说最核心的特点;普通队列是先进先出,而优先队列是"优先级高的先出",至于谁优先级高,是由比较规则决定的;底层实现一般是堆(heap),所以插入和删除的时间复杂度都是 O(log n),查询堆顶是 O(1)。

C++ 中的基本用法很固定;定义一个优先队列 priority_queue pq,这样默认就是大根堆;如果你想要小根堆,就要写成 priority_queue<int, vector, greater> pq;这个写法的意思是用 vector 存数据,用 greater 作为比较函数,让小的优先出来。

常用操作就几个;push(x) 把元素加入队列;pop() 删除队头元素(注意不会返回值);top() 查看当前队头;empty() 判断是否为空;size() 查看元素个数;这些操作和普通队列类似,但语义不同。

再说一个非常常见的用法,就是存 pair;比如在 Dijkstra 里,我们通常存 pair<距离, 节点编号>,并且用小根堆,这样每次取出的都是当前距离最小的点;写法是 priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;这里的比较是先比较 first,如果相等再比较 second。

优先队列最经典的应用有几个;第一是最短路径(Dijkstra),每次取当前距离最小的点;第二是哈夫曼树(合并果子),每次取最小的两个数;第三是一些"动态维护最大/最小值"的问题,比如不断加入元素并随时查询最大值。

最后讲一个容易踩的坑;priority_queue 不能像 vector 一样遍历,它不支持随机访问,如果你想看所有元素,只能不断 pop;另外,pop 只删除元素,不返回值,一定要先 top 再 pop;还有一点就是,如果你自定义结构体,一定要写比较规则,否则编译会报错。

总结一句:优先队列就是一个"随时能拿到当前最优元素"的工具,核心是堆结构,时间复杂度 O(log n),一旦题目出现"反复取最值",基本就可以考虑它。

相关推荐
小程故事多_801 天前
从A2C、TRPO、PPO到GRPO,强化学习策略梯度算法完整演进与大模型落地实战解析
人工智能·算法
2601_956121971 天前
二分算法(知识点+题目)
c++·算法
AndrewHZ1 天前
【LLM技术全景】阶段总结:技术原理篇核心知识回顾
人工智能·深度学习·算法·语言模型·大模型·llm·芯片开发
小星星闪亮登场1 天前
2026萌新联赛第三场-- (郑州轻工业大学)
数据结构·c++·经验分享·算法·贪心算法·排序算法·深度优先
冻柠檬飞冰走茶1 天前
PTA基础编程题目集 7-8超速判断(C++语言实现)
开发语言·数据结构·c++·算法
玖玥拾1 天前
LeetCode 88 合并两个有序数组
算法·leetcode
数据皮皮侠AI1 天前
上市公司数字供应链金融指数(2010-2024)
大数据·人工智能·算法
2501_942389551 天前
Epoch AI旗下FrontierMath的负责人Elliot Glazer
数据结构·决策树·动态规划·散列表
小程故事多_801 天前
用GRPO算法重塑多智能体系统,从原理落地到复杂任务规划实战
人工智能·算法
Hi李耶1 天前
【LeetCode】541.反转字符串 II
算法·leetcode·职场和发展