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

STL之priority_queue的用法与实现

 

目录

1. priority_queue的介绍 

1.1. priority_queue的概念

1.2. priority_queue的特点 

2. 仿函数 

2.1. 仿函数的概念

2.2. 仿函数的应用 

2.3 仿函数的灵活性 

3. priority_queue的用法 

4. 模拟实现priority_queue 

4.1. 插入 

4.2. 删除 

5. 源码 

priority_queue.h 

test.cpp 

结果 

 


💓 博客主页:C-SDN花园GGbond

⏩ 文章专栏:玩转c++

1. priority_queue的介绍 

1.1. priority_queue的概念

priority_queue即为**优先级队列,**它是STL对数据结构中堆的具体封装,因为priority_queue的头文件倍包含在queue的头文件中,所以使用时只需要包含头文件#include<queue>,并且使用优先级队列建堆,默认为大堆。

探索数据结构与算法】堆的具体实现和应用
 

 

1.2. priority_queue的特点 

priority_queue的模版参数有三个,第一个T是我们的元素类型第二个Container是我们的容器适配器第三个Compare是我们的仿函数。

priority_queue参考文档 

2. 仿函数 

2.1. 仿函数的概念

**仿函数(Functor)**是一种行为类似函数的对象,它可以被用作函数并接受参数。在 C++ 中,仿函数通常是重载了函数调用运算符 operator()的类对象。通过重载 operator(),仿函数可以像函数一样被调用,并且可以保存状态信息。

下面是一个具体的仿函数例子:

// 定义一个比较小于的仿函数
template<class T>
struct Less 
{//重载函数调用运算符 bool operator()(const T&a, const T&b)  {return a < b; }
};
int main() 
{Less<int> le;//定义一个仿函数对象int a = 5, b = 9;cout << le(a, b) << endl;//采用仿函数比较cout << (Less<int>().operator()(a,b)) << endl;//完整调用return 0;
}

我们可以通过定义对象的方式调用,也可以通过完整的类调用函数方式调用。

2.2. 仿函数的应用 

 在C++的标准库中,仿函数的使用就较为普遍,一般都作为模版参数进行传参。比如说算法库algorithm中的排序算法sort,默认排序就是升序,如果需要降序排序就需要传仿函数

这个仿函数或者函数我们可以自己定义,也可以借用标准库中提供的函数。其中比较常用的就是比较小于的less,比较大于的greater。使用时需要包含头文件#include<functional>

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<functional>
template<class T>
struct Less
{bool operator()(const T&a,const T&b){return a < b;}
};
template<class T>
struct Greater
{bool operator()(const T& a, const T& b){return a > b;}
};
int main()
{int a = 5,b = 9;less<int> Ls;cout << Ls(b, a) << endl;//采用仿函数比较cout << less<int>().operator()(a, b) << endl;//vector<int> v = { 2,3,1,7,5,6,9,8 };//sort(v.begin(), v.end());//默认升序sort(v.begin(), v.end(),greater<int>());//降序for (int& e : v){cout << e << " ";}cout << endl;return 0;
}

 

2.3 仿函数的灵活性 

 

仿函数 可以具有任意数量的参数,并可以用于各种不同的操作。这使得它们非常灵活,可以根据需要进行定制

在这个示例中,我们创建了两个不同的仿函数,一个用于加法(MyAdditionFunc),一个用于减法( MySubtractionFunc ),它们可以根据需要进行切换。

class MyAdditionFunc 
{
public:int operator()(int a, int b) {return a + b;}
};class MySubtractionFunc 
{
public:int operator()(int a, int b) {return a - b;}
};int main() 
{MyAdditionFunc add;MySubtractionFunc subtract;int result1 = add(5, 3);        // 8int result2 = subtract(5, 3);   // 2std::cout << "Result of addition: " << result1 << std::endl;std::cout << "Result of subtraction: " << result2 << std::endl;return 0;
}

 

3. priority_queue的用法 

priority_queue提供的接口相比较与其他容器也明显较少,这是由于其结构决定的,并且由于priority_queue也并不需要遍历,所以也不存在迭代器的概念。

以下就是priority_queue的接口:

我们学习过数据结构中的堆,所以使用这里的接口的成本也比较低。

void Test1()
{priority_queue<int> heap;heap.push(1);heap.push(2);heap.push(3);heap.push(4);heap.push(5);heap.push(6);cout << heap.size() << endl;cout << heap.top() << endl;while (!heap.empty()){cout << heap.top() << " ";heap.pop();}cout << endl;
}int main()
{Test1();return 0;
}

 

我们也可以使用greater仿函数让其变为小堆。

void Test1()
{priority_queue<int,vector<int>,greater<int>> heap;//第三个模板参数为仿函数类型heap.push(1);heap.push(2);heap.push(3);heap.push(4);heap.push(5);heap.push(6);cout << heap.size() << endl;cout << heap.top() << endl;while (!heap.empty()){cout << heap.top() << " ";heap.pop();}cout << endl;
}int main()
{Test1();return 0;
}

 

4. 模拟实现priority_queue 

我们学习过堆这个数据结构,所以封装priority_queue会非常简单,只需要在原有的基础上增加一个仿函数即可 

4.1. 插入 

 向堆的末尾插入新的元素,然后与父节点比较,然后判断是否需要向上调整。假设插入元素23,如下图:

 

//向上调整
void adjust_up(size_t child)
{Compare com;//使用仿函数,size_t parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}
void push(const T& val)
{_con.push_back(val);adjust_up(_con.size() - 1);
}
4.2. 删除 

 

先将堆顶元素与最后一个元素交换,将删除堆顶元素转化为删除末尾元素,然后再对堆顶元素进行向下调整。

 

 

//向下调整
void adjust_down(size_t parent)
{Compare com;size_t child = parent * 2 + 1;//左孩子while (child < _con.size()){//选出较大(小堆则较小)的那个孩子if (child + 1 < _con.size()&& com(_con[child], _con[child + 1]))child++;if (com(_con[parent], _con[child])){std::swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}
void pop()
{std::swap(_con[0], _con[_con.size() - 1]);_con.pop_back();
}

剩余的size()empty()top()等接口实现就非常容易了,这需要复用我们容器适配器的接口即可。 

const T& top()const
{return _con[0];
}
size_t size()const
{return _con.size();
}
bool empty()const
{return _con.empty();
}

5. 源码 

priority_queue.h 
#include<iostream>
#include<vector>
using namespace std;
template<class T>
class Less
{
public:bool operator()(const T& x, const T& y){return x < y;}
};
template<class T>
class Greater
{
public:bool operator()(const T& x, const T& y){return x > y;}
};
namespace HTD
{//template<class T,class Container=vector<T>,class compare=Greater<T>>template<class T, class Container = vector<T>, class compare =Less<T>>class priority_queue{public:void AdjustUp(int child){compare com;int parent = (child - 1) / 2;while (child > 0){if(com(_con[parent],_con[child]))//if (_con[parent] < _con[child]){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){_con.push_back(x);AdjustUp(_con.size() - 1);}void AdjustDown(int parent){compare com;int child = 2 * parent + 1;while (child < _con.size()){//if (child + 1 < _con.size() && _con[child ] < _con[child+1])if (child + 1 < _con.size() && com(_con[child],_con[child+1])) // 选出较大(小堆则较小)的那个孩子{child++;}//if (_con[parent] < _con[child])if(com(_con[parent],_con[child])){swap(_con[parent], _con[child]);parent = child;child = child * 2 + 1;}else{break;}}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}const T& top(){return _con[0];}bool empty()const{return _con.empty();}size_t size()const{return _con.size();}private:Container _con;};
}
test.cpp 
#include"priority_queue.h"
int main()
{//priority_queue<int, vector<int>> pq;HTD:: priority_queue<int, vector<int>> pq;pq.push(4);pq.push(1);pq.push(5);pq.push(7);pq.push(9);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;}
结果 

 


 

相关文章:

STL之priority_queue的用法与实现

目录 1. priority_queue的介绍 1.1. priority_queue的概念 1.2. priority_queue的特点 2. 仿函数 2.1. 仿函数的概念 2.2. 仿函数的应用 2.3 仿函数的灵活性 3. priority_queue的用法 4. 模拟实现priority_queue 4.1. 插入 4.2. 删除 5. 源码 priority_…...

深度学习中的数值稳定性处理详解:以SimCLR损失为例

文章目录 1. 问题背景SimCLR的原始公式 2. 数值溢出问题为什么会出现数值溢出&#xff1f;浮点数的表示范围 3. 数值稳定性处理方法核心思想数学推导 4. 代码实现分解代码与公式的对应关系 5. 具体数值示例示例&#xff1a;相似度矩阵方法1&#xff1a;直接计算exp(x)方法2&…...

散户使用算法交易怎么做?

智能算法交易是量化交易里面最常见的一种&#xff0c;也是大多数散户被套住的股票&#xff0c;想要解套&#xff0c;降低成本最直接有效的方式。但是往往这种波动速度小&#xff0c;担心速度跟不上的情况&#xff0c;我们就要叠加快速通道。 第一&#xff1a;算法交易的应用场…...

Docker详细使用

Docker详细使用 文章目录 Docker详细使用使用场景docker安装常用命令帮助启动类命令镜像命令网络命令容器命令compose&#xff08;服务编排&#xff09; 功能列表存储&#xff08;挂载本地&#xff09;介绍使用⽬录挂载卷映射 网络介绍使用 DockerfileCompose介绍使用 使用场景…...

mongodb 安装配置

1.官网下载地址&#xff1a;MongoDB Community Download | MongoDB 2.解压包安装&#xff1a;https://pan.baidu.com/s/1Er56twK9UfxoExuCPlJjhg 提取码: 26aj 3.配置环境&#xff1a; &#xff08;1&#xff09;mongodb安装包位置&#xff1a; &#xff08;2&#xff09;复…...

CSV文件中的中文乱码--UTF-8 with BOM

文章目录 1. 现象2. 原因3. BOM3.1 什么是BOM&#xff1f;3.2 BOM的作用3.3 特殊性 4. 如何解决乱码&#xff1f;4.1 手动设置格式4.2 自动设置格式4.2.1 Python如何设置&#xff1a;4.2.2 java如何设置 1. 现象 在使用了UTF-8格式编码之后&#xff0c;CSV文件在Excel中打开还…...

榕壹云酒水定制系统:基于THinKPHP+MySQL+UniApp打造数字化时代的个性化购酒新体验

数字化浪潮下的酒水定制新机遇 在消费升级与个性化需求崛起的背景下,传统酒水行业正面临数字化转型的迫切需求。为此,我们团队基于ThinkPHP+MySQL+UniApp技术栈,开发了一套榕壹云酒水定制系统,旨在通过数字化手段解决消费者个性化购酒痛点,为酒类品牌提供全链路数字化解决…...

Leetcode——137 260找出只出现一次的数

文章目录 找出只出现一次的数引入Leetcode 260Leetcode 137 找出只出现一次的数 对于数组中有一类题&#xff0c;即某些数据在数组中只出现一遍&#xff0c;需要我们找出&#xff0c;今天我们来看看这个类型的题。 引入 想必大家应该见过这么一道题&#xff1a; 现给定一个数…...

算法:定义一个数组的的陡峭值为:相邻两个元素之差的绝对值之和。

定义一个数组的的陡峭值为:相邻两个元素之差的绝对值之和。现在小红拿到了一个数组&#xff0c;她有多次询问&#xff0c;每次查询一段连续子数组的陡峭值。你能帮帮她吗? 连续子数组为从原数组中&#xff0c;连续的选择一段元素(可以全选、可以不选)得到的新数组。 输入描述 …...

uniapp自定义tabbar,根据角色动态显示不同tabbar,无闪动问题

🤵 作者:coderYYY 🧑 个人简介:前端程序媛,目前主攻web前端,后端辅助,其他技术知识也会偶尔分享🍀欢迎和我一起交流!🚀(评论和私信一般会回!!) 👉 个人专栏推荐:《前端项目教程以及代码》 ✨一、前言 这个需求在开发中还是很常见的,搜索了网络其他教程,…...

OpenTiny使用指南

最近项目里用到了一个新的组件库——OpenTiny&#xff0c;但是官方文档的使用指南的描述很复杂&#xff0c;花了一些时间尝试才正常使用。下面是一个使用步骤的描述&#xff0c;可放心食用&#xff1a; 一、安装 TinyVue 组件库同时支持 Vue 2.0 和 Vue 3.0 框架&#xff0c;…...

《一文讲透》第7期:KWDB 巧用标签与索引优化查询性能

引言 在工业物联网快速发展的今天&#xff0c;各类智能传感器设备已广泛应用于智能制造、能源电力、智慧城市等关键领域。这些设备以极高的采样频率持续产生监测数据&#xff0c;使得单条产线每秒产生数十万条传感器数据已成为行业常态&#xff0c;这对数据存储系统的写入吞吐…...

KingbaseES之KDts迁移SQLServer

项目适配迁移SQLServer至金仓,今天写写KDts-WEB版迁移工具迁移SQLServer至KingbaseES的步骤,以及迁移注意事项. SQLServer版本:SQLServer2012 KingbaseES版本:V009R004C011(SQLServer兼容版) --1.进入数据库客户端工具KDTS工具目录&#xff0c;启动KDts服务&#xff1a; [king…...

13-scala模式匹配

模式匹配是检查某个值&#xff08;value&#xff09;是否匹配某一个模式的机制&#xff0c;一个成功的匹配同时会将匹配值解构为其组成部分。它是Java中的switch语句的升级版&#xff0c;同样可以用于替代一系列的 if/else 语句。 语法 一个模式匹配语句包括一个待匹配的值&a…...

代码随想录动态规划part02

动态规划part02 62.不同路径 代码随想录 视频讲解&#xff1a;动态规划中如何初始化很重要&#xff01;| LeetCode&#xff1a;62.不同路径_哔哩哔哩_bilibili 递归法 动态规划&#xff0c;当前状态是由上一个状态转化来的 这里初始化错误了&#xff0c;想法是对的右一和…...

数据结构-限定性线性表 - 栈与队列

栈和队列是数据结构中非常重要的两种限定性线性表&#xff0c;它们在实际应用中有着广泛的用途。这篇文章将深入讲解栈和队列的概念、抽象数据类型、实现方式、应用场景以及性能分析&#xff0c;并通过代码示例帮助大家更好地理解和实践。 一、栈的概念与抽象数据类型 1.1 栈…...

详解如何复现DeepSeek R1:从零开始利用Python构建

DeepSeek R1 的整个训练过程&#xff0c;说白了就是在其基础模型&#xff08;也就是 deepseek V3&#xff09;之上&#xff0c;用各种不同的强化学习方法来“雕琢”它。 咱们从一个小小的本地运行的基础模型开始&#xff0c;一边跟着 DeepSeek R1 技术报告 的步骤&#xff0c;…...

Java集合框架 源码分析 迭代器 并发修改异常底层原理

迭代器 Java中的Iterator&#xff08;迭代器&#xff09;是集合框架中用于遍历容器元素的统一接口&#xff0c;提供了一种标准化的元素访问方式&#xff0c;无需依赖具体集合类型的实现细节。以下是其核心要点&#xff1a; 一、核心方法与使用步骤 获取迭代器 通过集合的 it…...

CentOS7更换国内YUM源和Docker简单应用

配置国内阿里云镜像源 ## 更新镜像源 # 1.备份 cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak# 2.替换镜像源文件 curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo# 3.生成缓存 yum clean all yum m…...

Cannot find module ‘vue‘ or its corresponding type declarations

在使用vue3vite创建新的工程时&#xff0c;在新增.vue文件时会出现Cannot find module vue这个错误。 只需要我们在项目中的.d.ts文件中添加以下代码即可 declare module *.vue {import { defineComponent } from vue;const component: ReturnType<typeof defineComponent&…...

【Python爬虫】详细工作流程以及组成部分

目录 一、Python爬虫的详细工作流程 确定起始网页 发送 HTTP 请求 解析 HTML 处理数据 跟踪链接 递归抓取 存储数据 二、Python爬虫的组成部分 请求模块 解析模块 数据处理模块 存储模块 调度模块 反爬虫处理模块 一、Python爬虫的详细工作流程 在进行网络爬虫工…...

欧拉服务器操作系统部署deekseep(Ollama+DeekSeep+open WebUI)

​​一、解压并安装 Ollama​​ # 1. 解压文件&#xff08;默认会得到一个二进制文件&#xff09; tar -xzvf ollama-linux-amd64.tgz# 2. 将二进制文件安装到系统路径 sudo mv ollama /usr/local/bin/ sudo chmod x /usr/local/bin/ollama# 3. 验证安装 ollama --version链接…...

报错:Nlopt

报错&#xff1a;Nlopt CMake Error at TGH-Planner/fast_planner/bspline_opt/CMakeLists.txt:20 (find_package):By not providing "FindNLopt.cmake" in CMAKE_MODULE_PATH this project hasasked CMake to find a package configuration file provided by "…...

#4 我们为什么使用物联网? 以及 物联网的整体结构

设备不物联是否可以&#xff1f; 答案 是可以的&#xff0c;从项目实战的角度&#xff0c;还是有很多包括分拣&#xff0c;控制&#xff0c;检测等应用是分立的&#xff0c;这个和成本&#xff0c;场景&#xff0c;客户接受度等因素有关。 局部看&#xff0c;一些系统的确很简…...

centOS 安装和配置docker

以下是在 CentOS 系统上安装和配置 Docker 的详细步骤&#xff1a; 一、安装 Docker 1. 卸载旧版本&#xff08;如有&#xff09; sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate …...

3D版的VLA——从3D VLA、SpatialVLA到PointVLA(不动VLM,仅动作专家中加入3D数据)

前言 之前写这篇文章的时候&#xff0c;就想解读下3D VLA来着&#xff0c;但一直因为和团队并行开发具身项目&#xff0c;很多解读被各种延后 更是各种出差&#xff0c;比如从25年3月下旬至今&#xff0c;连续出差三轮&#xff0c;绕中国半圈&#xff0c;具身占八成 第一轮 …...

linux Shell编程之循环语句(三)

目录 一. for 循环语句 1. for语句的结构 2. for 语句应用示例 (1) 根据姓名列表批量添加用户 (2) 根据 IP 地址列表检查主机状态 二. 使用 while 循环语句 1. while 语句的结构 2. while 语句应用示例 (1) 批量添加规律编号的用户 (2) 猜价格游戏 三. until 循环语…...

C#容器源码分析 --- Queue<T>

Queue<T> 是 System.Collections.Generic 命名空间下的先进先出&#xff08;FIFO&#xff09;动态集合&#xff0c;其核心实现基于​​循环数组​​&#xff0c;通过维护头尾指针实现高效入队和出队操作。 .Net4.8 Queue<T>源码地址&#xff1a;queue.cs (microso…...

ViT 模型讲解

文章目录 一、模型的诞生背景1.1 背景1.2 ViT 的提出&#xff08;2020年&#xff09; 二、模型架构2.1 patch2.2 模型结构2.2.1 数据 shape 变化2.2.2 代码示例2.2.3 模型结构图 2.3 关于空间信息 三、实验3.1 主要实验3.2 消融实验 四、先验问题4.1 归纳偏置4.2 先验or大数据&…...

IntelliJ IDEA 中安装和使用通义灵码 AI 编程助手教程

随着人工智能技术的发展&#xff0c;AI 编程助手逐渐成为提升开发效率的强大工具。通义灵码是阿里云推出的一款 AI 编程助手&#xff0c;它能够帮助开发者实现智能代码补全、代码解释、生成单元测试等功能&#xff0c;极大地提升了编程效率和代码质量。 IntelliJ IDEA 是一款广…...