下面是关于 C++ 中 std::priority_queue 的详细说明,包括初始化、用法和常见的应用场景。


什么是 priority_queue

priority_queue(优先队列)是 C++ 标准库中的一个容器适配器。它和普通队列(queue)最大的不同在于,元素的出队顺序不是根据它们入队的顺序(先进先出),而是根据它们的优先级

默认情况下,priority_queue 是一个大顶堆(Max-Heap),意味着优先级最高的元素是值最大的元素。每次调用 top() 都会返回当前队列中最大的元素。

  • 底层实现:通常使用**堆(Heap)**数据结构来实现,这使得它能以对数时间复杂度(O(log n))插入元素和删除最大(或最小)的元素。
  • 头文件:使用前需要包含头文件 <queue>
#include <iostream>
#include <queue>
#include <vector>
#include <functional> // 包含 std::greater 和 std::less

1. priority_queue 的初始化

priority_queue 的模板定义如下:

template <class T, class Container = std::vector<T>, class Compare = std::less<typename Container::value_type>>
class priority_queue;
  • T: 存储的元素类型。
  • Container: 用于存储元素的底层容器,默认为 std::vector<T>。必须是支持随机访问迭代器和 front(), push_back(), pop_back() 等操作的序列容器,例如 std::vectorstd::deque
  • Compare: 比较函数或函数对象,用于确定元素的优先级。默认为 std::less<T>,它会创建一个大顶堆。
1.1 默认初始化(大顶堆)

最常见的用法,创建一个存储 int 类型的大顶堆。每次 top() 都会返回最大的元素。

// 默认情况下,是 std::vector 作为容器,std::less 作为比较函数,即大顶堆
std::priority_queue<int> max_heap;max_heap.push(30);
max_heap.push(100);
max_heap.push(25);
max_heap.push(40);// 此刻队列顶部的元素是 100
std::cout << "Top element is: " << max_heap.top() << std::endl; // 输出 100
1.2 初始化为小顶堆

如果你想让 top() 总是返回最小的元素,你需要创建一个小顶堆(Min-Heap)。这需要显式提供所有模板参数:

  • T: 元素类型。
  • Container: 底层容器,通常是 std::vector<T>
  • Compare: 比较函数,使用 std::greater<T>
// 使用 std::greater<int> 来创建小顶堆
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;min_heap.push(30);
min_heap.push(100);
min_heap.push(25);
min_heap.push(40);// 此刻队列顶部的元素是 25
std::cout << "Top element is: " << min_heap.top() << std::endl; // 输出 25
1.3 存储自定义结构体

当存储自定义类型(如 structclass)时,你需要告诉优先队列如何比较它们。有两种主要方法:

方法一:重载 < 运算符(用于大顶堆)

struct Node {int id;int priority;// 重载 < 运算符,priority 越大,优先级越高bool operator<(const Node& other) const {return this->priority < other.priority;}
};std::priority_queue<Node> pq;
pq.push({1, 10});
pq.push({2, 5});
pq.push({3, 20});// top() 将返回 priority 最大的 Node,即 {3, 20}
std::cout << "Top node: id=" << pq.top().id << ", priority=" << pq.top().priority << std::endl;

方法二:提供自定义比较器(更灵活)

如果你不想或不能修改结构体定义,或者需要多种排序方式,可以提供一个自定义的比较函数对象(Functor)。

struct Node {int id;int priority;
};// 自定义比较器结构体
struct CompareNode {// 返回 true 表示 a 的优先级低于 bbool operator()(const Node& a, const Node& b) {// 创建小顶堆,priority 越小,优先级越高return a.priority > b.priority;}
};std::priority_queue<Node, std::vector<Node>, CompareNode> pq;
pq.push({1, 10});
pq.push({2, 5});
pq.push({3, 20});// top() 将返回 priority 最小的 Node,即 {2, 5}
std::cout << "Top node: id=" << pq.top().id << ", priority=" << pq.top().priority << std::endl;

使用 Lambda 表达式(C++11及以上)也可以实现,但定义比较器时需要 decltype

1.4 从已有容器初始化

你可以用一个已有的容器(如 vector)中的元素来初始化优先队列。

std::vector<int> data = {30, 100, 25, 40};// 从 data 初始化一个大顶堆
std::priority_queue<int> max_heap_from_vec(data.begin(), data.end());std::cout << "Top element from vector init: " << max_heap_from_vec.top() << std::endl; // 输出 100// 初始化小顶堆
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap_from_vec(data.begin(), data.end());
std::cout << "Top element from vector init (min-heap): " << min_heap_from_vec.top() << std::endl; // 输出 25

2. priority_queue 的常用操作

优先队列的操作非常简单直观:

  • push(element): 向队列中插入一个元素。时间复杂度 O(log n)。
  • pop(): 移除队首(优先级最高)的元素。时间复杂度 O(log n)。
  • top(): 返回队首(优先级最高)元素的常引用,不删除元素。时间复杂度 O(1)。
  • empty(): 检查队列是否为空。
  • size(): 返回队列中元素的数量。

示例代码:

std::priority_queue<int> pq;std::cout << "Is queue empty? " << (pq.empty() ? "Yes" : "No") << std::endl;pq.push(10);
pq.push(50);
pq.push(20);std::cout << "Queue size: " << pq.size() << std::endl;
std::cout << "Top element: " << pq.top() << std::endl; // 50pq.pop(); // 移除了 50std::cout << "Top element after pop: " << pq.top() << std::endl; // 20// 遍历并清空优先队列
std::cout << "Queue elements in priority order: ";
while (!pq.empty()) {std::cout << pq.top() << " ";pq.pop();
}
std::cout << std::endl;
// 输出: Queue elements in priority order: 20 10

注意priority_queue 没有提供迭代器,不能像 vector 那样直接遍历。唯一的访问方式就是通过 top() 获取队首元素。


3. priority_queue 的应用场景

优先队列在算法和系统设计中非常有用,尤其适合处理那些需要动态维护“最大/最小”元素的问题。

3.1 Top-K 问题

这是最经典的应用。例如,从一个巨大的数据流中找出最大的 K 个元素。

思路

  • 维护一个大小为 K 的小顶堆
  • 遍历数据流,对于每个新元素:
    • 如果堆的大小小于 K,直接将元素插入堆中。
    • 如果堆的大小等于 K,将新元素与堆顶元素(当前 K 个元素中最小的那个)比较。
    • 如果新元素大于堆顶元素,则弹出堆顶,并将新元素插入。
  • 遍历结束后,堆中剩下的 K 个元素就是最大的 K 个元素。

为什么用小顶堆? 因为小顶堆的堆顶是“门槛”,只有比这个门槛大的元素才有资格进入这个“Top-K 圈子”,这样可以高效地淘汰掉不够大的元素。

3.2 堆排序(Heap Sort)

虽然 C++ 提供了 std::sort,但优先队列可以很自然地实现堆排序。

  1. 将所有元素插入一个大顶堆。
  2. 依次从堆中取出堆顶元素,放入结果数组中。取出的顺序就是从大到小。
3.3 Dijkstra 算法

在图论中,Dijkstra 算法用于寻找图中单源最短路径。算法的核心是每次都从“待处理”的顶点中,选择一个距离源点最近的顶点进行扩展。优先队列(小顶堆)可以完美地胜任这个任务。

  • 优先队列中存储 pair<int, int>,即 {距离, 顶点编号}
  • 每次从队列中取出 top(),就是当前距离源点最近的未访问顶点。
3.4 Huffman 编码

在数据压缩中,Huffman 编码算法使用优先队列来构建最优二叉树(Huffman 树)。

  • 将每个字符及其频率作为一个节点放入一个优先队列(小顶堆)中,频率越小,优先级越高。
  • 每次从队列中取出两个频率最小的节点,合并成一个新的父节点(频率为两者之和),再将新节点放回优先队列。
  • 重复此过程,直到队列中只剩一个节点,即 Huffman 树的根。
3.5 任务调度系统

在操作系统或中间件中,任务调度器需要从多个待执行的任务中选择一个优先级最高的来执行。优先队列可以用来管理这些任务,top() 总是返回当前最紧急的任务。


希望这份详细的说明对你有帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88272.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88272.shtml
英文地址,请注明出处:http://en.pswp.cn/web/88272.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

零基础入门物联网-远程门禁开关:硬件介绍

一、成品展示 远程门禁最终效果 二、项目介绍 整个项目主要是实际使用案例为主&#xff0c;根据自己日常生活中用到物联网作品为原型&#xff0c;通过项目实例快速理解。项目分为两部分&#xff1a;制作体验和深入学习。 制作体验部分 会提供所有项目资料及制作说明文档&a…

软件系统国产化改造开发层面,达梦(DM)数据库改造问题记录

本系统前&#xff08;vue&#xff09;后端(java spring boot)为列子&#xff0c;数据库由MySQL--->DM&#xff08;达梦&#xff09;&#xff0c;中间件为中创的国产化相关软件&#xff0c;如tomcat、nginx、redis等。重点讲数据库及代码端的更改&#xff0c;中间件在服务端以…

N8N与Dify:自动化与AI的完美搭配

“N8N”和“Dify”这两个工具彻底理清楚&#xff0c;它们其实是两个定位完全不同的开源平台&#xff0c;各自擅长解决不同类型的问题&#xff0c;但也能协同工作。以下是详细说明&#xff1a;1. n8n&#xff1a;工作流自动化平台定位&#xff1a;n8n 是一个专注于跨系统连接与任…

ARM汇编编程(AArch64架构)课程 - 第5章函数调用规范

目录AAPCS64调用约定参数传递规则返回值规则栈帧管理SP寄存器FP寄存器 (X29)栈帧布局示例AAPCS64调用约定 ARM Architecture Procedure Call Standard for 64-bit (AAPCS64) 参数传递规则 参数位置寄存器分配特殊规则参数1-8X0-X7 (64-bit) / W0-W7 (32-bit)浮点数使用 V0-V7参…

软考(软件设计师)软件工程-成本评估模型,软件能力成熟度,软件配置管理

成本评估模型 Putnam 下面通过一个具体案例&#xff0c;逐步说明Putnam模型的计算过程。我们将开发一个银行核心交易系统&#xff0c;规模为80万行代码&#xff08;LOC&#xff09;&#xff0c;要求24个月内交付。参数符号值说明软件规模L800,000 LOC通过功能点转换获得开发时间…

SASSNet复现

复现结果–Dice&#xff1a;89.354614&#xff0c;Jaccard&#xff1a;80.968917&#xff0c;95HD&#xff1a;7.3987764&#xff0c;误差在接受范围 MethodDiceJaccardJaccard # 感想 第19篇完全复现的论文

大数据学习5:网站访问日志分析

1.数据处理1.1 环境准备进入cd /opt/server/hadoop-3.1.0/sbin文件夹&#xff0c;停止hdfs服务cd /opt/server/hadoop-3.1.0/sbin ./stop-dfs.sh进入/opt/server/hadoop-3.1.0/etc/hadoop文件夹&#xff0c;编辑yarn-site.xml文件/opt/server/hadoop-3.1.0/etc/hadoop vim yarn…

力扣1310. 子数组异或查询

这一题很明显的就是用前缀和异或来解决&#xff0c;只要清楚异或的性质&#xff0c;这一题就十分容易。 对异或的性质的讲解如下&#xff1a; 异或运算解析 具体代码如下&#xff1a; class Solution { public:int sum[30005]; vector<int> xorQueries(vector<int>…

React Native 状态管理方案全面对比

React Native 状态管理方案全面对比 在 React Native 开发中&#xff0c;状态管理是构建复杂应用的核心问题。以下是主流状态管理方案的深度对比分析&#xff1a; 一、基础方案&#xff1a;useState/useReducer 适用场景 简单的组件级状态中等复杂度的局部状态管理不需要跨组件…

基于Python的程序员数据分析与可视化系统的设计与实现

文章目录有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍背景意义项目展示总结每文一语有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 互联网技术飞速发展&#xff0c;数据分析与可视化在程序员工…

Java 枚举详解:从基础到实战,掌握类型安全与优雅设计

作为一名Java开发工程师&#xff0c;在日常开发中你一定经常使用枚举&#xff08;enum&#xff09;。自Java 5引入以来&#xff0c;枚举已经成为定义固定集合常量的首选方式&#xff0c;它比传统的 public static final 常量更加类型安全、可读性强&#xff0c;并且具备面向对象…

海外盲盒系统:技术如何重构“信任经济”?

盲盒的“非透明性”易引发信任危机&#xff0c;而海外盲盒系统通过技术手段构建了“可感知的公平”&#xff1a;1. 区块链存证&#xff1a;概率透明化 隐藏款概率、抽盒记录上链存证&#xff0c;用户可随时查询历史数据。某欧美用户通过区块链浏览器验证&#xff0c;确认系统隐…

PyTorch Tensor 操作入门:转换、运算、维度变换

目录 1. Tensor 与 NumPy 数组的转换 1.1 Tensor 转换为 NumPy 数组 1.2 NumPy 数组转换为 Tensor 1.3 获取单个元素的值 2. Tensor 的基本运算 2.1 生成新 Tensor 的运算 2.2 覆盖原 Tensor 的运算 2.3 阿达玛积&#xff08;逐元素乘法&#xff09; 2.4 矩阵乘法 3.…

CompletableFuture使用详解(Super Detailed)

一、 CompletableFuture介绍 多线程开发一般使用Runnable&#xff0c;Callable&#xff0c;Thread&#xff0c;FutureTask&#xff0c;ThreadPoolExecutor&#xff0c;但也有不近如意的地方 Thread Runnable&#xff1a;执行异步任务&#xff0c;没有返回结果。 Thread Calla…

开源 Arkts 鸿蒙应用 开发(六)数据持久--文件和首选项存储

文章的目的为了记录使用Arkts 进行Harmony app 开发学习的经历。本职为嵌入式软件开发&#xff0c;公司安排开发app&#xff0c;临时学习&#xff0c;完成app的开发。开发流程和要点有些记忆模糊&#xff0c;赶紧记录&#xff0c;防止忘记。 相关链接&#xff1a; 开源 Arkts …

【Bluedroid】蓝牙协议栈控制器能力解析与核心功能配置机制(decode_controller_support)

本文围绕Bluedroid蓝牙协议栈中控制器能力解析与核心功能配置的关键代码展开&#xff0c;详细阐述蓝牙协议栈如何通过解析控制器硬件能力&#xff0c;构建 SCO/eSCO、ACL 数据包类型支持掩码&#xff0c;配置链路策略、安全服务、查询与扫描模式等核心功能。这些机制确保协议栈…

小架构step系列07:查找日志配置文件

1 概述 日志这里采用logback&#xff0c;其为springboot默认的日志工具。其整体已经被springboot封装得比较好了&#xff0c;扔个配置文件到classpath里就能够使用。 但在实际使用中&#xff0c;日志配置文件有可能需要进行改动&#xff0c;比如日志的打印级别&#xff0c;平…

一文讲清楚React Hooks

文章目录一文讲清楚React Hooks一、什么是 React Hooks&#xff1f;二、常用基础 Hooks2.1 useState&#xff1a;状态管理基本用法特点2.2 useEffect&#xff1a;副作用处理基本用法依赖数组说明2.3 useContext&#xff1a;上下文共享基本用法特点三、其他常用 Hooks3.1 useRed…

Apache http 强制 https

1. 修改一下文件配置 sudo nano /etc/apache2/sites-enabled/000-default.conf<VirtualHost *:80>ServerName hongweizhu.comServerAlias www.hongweizhu.comServerAdmin webmasterlocalhostDocumentRoot /var/www/html# 强制重定向到HTTPSRewriteEngine OnRewriteCond …

【读代码】GLM-4.1V-Thinking:开源多模态推理模型的创新实践

一、基本介绍 1.1 项目背景 GLM-4.1V-Thinking是清华大学KEG实验室推出的新一代开源视觉语言模型,基于GLM-4-9B-0414基础模型构建。该项目通过引入"思维范式"和强化学习课程采样(RLCS)技术,显著提升了模型在复杂任务中的推理能力。其创新点包括: 64k超长上下文…