【C++】优先级队列(容器适配器)
欢迎来到我的Blog,点击关注哦💕
前言
stringvectorlist这种线性结构是最基础的存储结构,C++(STL)container很好的帮助我们数据存储的问题。
容器适配器
介绍
- 容器适配器是C++标准模板库(
STL)中的一种设计模式,它允许将一个容器的接口转换为另一个接口,从而提供不同的操作和行为。 - 容器适配器通常用于封装现有容器,以实现特定的数据结构特性,如栈(后进先出)、队列(先进先出)和优先队列(根据优先级排序)。
应用
-
栈(stack):栈是一种后进先出的数据结构,其操作包括入栈(push)、出栈(pop)、查看栈顶元素(top)等。栈适配器可以基于多种底层容器实现,如
vector、deque或list. -
队列(queue):队列是一种先进先出的数据结构,其操作包括入队(push)、出队(pop)、查看队首元素(front)和查看队尾元素(back)。队列适配器同样可以基于
deque或list实现,以适应不同的性能需求. -
优先队列(priority_queue):优先队列是一种特殊的队列,它根据元素的优先级进行排序。其底层容器通常是
vector或deque,并通过堆算法维护元素的优先级顺序。优先队列适配器提供了插入和删除具有最高优先级元素的操作.
双重结束队列(双端队列(deque))
特点
- 双端操作效率:支持在两端进行快速的插入和删除操作。
- 随机访问:可以通过索引直接访问容器中的元素。
- 无需预先分配固定大小:与
vector不同,deque不需要在创建时指定大小,它可以根据需要动态增长。 - 内存分配策略:
deque不需要像vector那样一次性分配大量内存,而是分散在内存中,这有助于减少内存碎片。
存储结构
双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落 在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:

List 、vector deque对比
| 对比维度 | Vector | Deque | List |
|---|---|---|---|
| 内存连续性 | 是 | 否 | 否 |
| 随机访问性能 | O(1) | O(1) 但可能不如Vector | O(n) |
| 插入/删除性能 | 非末尾O(n) | 两端O(1), 中间O(n) | 两端及中间O(1) |
| 内存重用效率 | 扩容时需移动元素 | 两端添加删除不需移动 | 不适用 |
| 内存分配模式 | 动态数组,连续内存 | 分段连续内存 | 非连续内存 |
| 迭代器失效 | 可能 | 不会 | 不会 |
| 支持的操作 | [] 访问、.at() 等 | [] 访问、.at() 等 | [] 访问、.at() 等 |
| 内存管理开销 | 高(扩容时) | 中等(两端操作) | 低 |
| 适用场景 | 需要快速随机访问且元素数量稳定 | 需要两端快速插入删除,随机访问需求适中 | 频繁插入删除,不关心随机访问 |
栈(stack)
栈的介绍
| 函数说明 | 接口说明 |
|---|---|
| stack() | 构造空的栈 |
| empty() | 检测stack是否为空 |
| size() | 返回stack中元素的个数 |
| top() | 返回栈顶元素的引用 |
| push() | 将元素val压入stack中 |
| pop() | 将stack中尾部的元素弹出 |
栈的模拟实现
利用容器适配器的设计原理,很容易实现栈
- 将栈放
mystack的命名空间,以防止和库中冲突 - 类模板设计
container可以给缺省参数,默认deque(容器适配器) - 在里面利用
deque的接口实现
namespace mystack
{template<class T, class Container = std::deque<T>>class stack{public:void push_back(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}size_t size(){return _con.size();}T& top(){return _con.back();}bool empty(){return _con.empty();}private:Container _con;};
}
队列
队列介绍
| 函数声明 | 接口说明 |
|---|---|
| queue() | 构造空的队列 |
| empty() | 检测队列是否为空,是返回true,否则返回false |
| size() | 返回队列中有效元素的个数 |
| front() | 返回队头元素的引用 |
| back() | 返回队尾元素的引用 |
| push() | 在队尾将元素val入队列 |
| pop() | 将队头元素出队列 |
队列模拟实现
- 将栈放
myqueue的命名空间,以防止和库中冲突 - 类模板设计
container可以给缺省参数,默认deque(容器适配器) - 在里面利用
deque的接口实现
namespace myqueue
{template<class T, class Container = std::deque<T >>class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}size_t size(){return _con.size();}T& front(){return _con.front();}bool empty(){return _con.empty();}private:Container _con;};
}
优先级队列(priority_queue)
基本原理
- 优先级队列通常在内部使用堆数据结构来维护元素的优先级。
- 堆是一种完全二叉树,可以是最大堆或最小堆。
- 在最大堆中,父节点的值总是大于或等于其子节点的值,而在最小堆中,父节点的值总是小于或等于其子节点的值。
- 插入操作通过在堆的适当位置插入新元素并进行上调整(
heapify-up)来维持堆的性质。 - 删除操作则涉及到移除堆顶元素(优先级最高的元素)并进行下调整(
heapify-down),以恢复堆的结构。
priority_queue介绍
| 函数声明 | 接口说明 |
|---|---|
| priority_queue()/priority_queue(first, last) | 构造一个空的优先级队列 |
| empty( ) | 检测优先级队列是否为空,是返回true,否则返回 false |
| top( ) | 返回优先级队列中最大(最小元素),即堆顶元素 |
| push(x) | 在优先级队列中插入元素x |
| pop() | 删除优先级队列中最大(最小)元素,即堆顶元素 |
优先级模拟实现 (可以参考)
仿函数
- 仿函数(Functor)是C++中的一个编程概念,它指的是一个类或结构体,通过重载函数调用运算符
operator(),使得这个类或结构体的对象可以像函数一样被调用。 - 仿函数可以包含状态,因为它们是对象,可以在构造函数中初始化状态,并在
operator()中使用该状态。 - 仿函数可以作为参数传递给其他函数,包括
STL算法中的函数,从而提供灵活的编程模型.
这个就是一个仿函数
//小于
template<class T>class Less{public:bool operator()(const T& a,const T& b){return a < b;}};
//大于
template<class T>class Greater{public:bool operator()(const T& x, const T& y){return x > y;}};
priority_queue两个关键
向下建堆
- 确定起始点:从最后一个非叶子节点开始向下建堆,这个节点也被称为堆的最后一个非叶子节点。在完全二叉树中,最后一个非叶子节点的索引可以通过
(n - 1 - 1) / 2计算得到,其中n是数组的长度。 - 执行向下调整:对每个非叶子节点执行向下调整操作,确保该节点与其子节点组成的子树满足堆的性质。向下调整的过程涉及到与子节点的比较和必要时的交换,直至到达堆的顶部或直到父节点不再违反堆的性质。
- 迭代过程:从最后一个非叶子节点开始,逐步向上调整,直到根节点。每次调整后,更新当前节点的索引,以便进行下一次调整。
- 完成建堆:重复步骤2和步骤3,直到根节点也满足堆的性质,此时整个数组就构建成了一个堆。
void AdjustDown(size_t parent)
{compare com;//仿函数size_t child = parent * 2 + 1;//if (child+1< _con.size() && _con[child] < _con[1+child])if (child + 1 < _con.size() && com(_con[child] ,_con[1 + child]))//和上面等价{++child;}while (child <_con.size()){if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
向上建堆
- 初始化堆大小**:设置堆的大小为数组的大小,即
n。 - 从最后一个非叶子节点开始向上调整:在完全二叉树中,最后一个非叶子节点的索引为
floor((n - 1) / 2)。从这个节点开始向上调整,确保每个节点都满足大根堆的性质。 - 执行向上调整操作:对于每个非叶子节点,检查其与子节点的关系,并进行必要的交换,以确保父节点的值大于或等于其子节点的值。如果子节点中有一个或两个,选择较大的子节点与父节点进行比较。如果父节点的值小于子节点的值,交换它们的位置,并重新设置父节点为当前子节点,继续向上调整。
- 重复步骤2和3:直到达到根节点,即堆的第一个元素。
void AdjustUp(int child)
{compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent] , _con[child])){std::swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}
初始化数据
迭代器初始化
-
模板嵌套给,迭代器初始化
-
依次
push数据,在进行堆的建立
template<class InputIterator>
void push_back(InputIterator first, InputIterator last){while (first != last){_con.push_back(*first);++first;}//向下建堆for (int i = (_con.size() - 2) / 2; i >= 0; i--){AdjustDown(i);}}
pop数据
- 将一个个数据和最后一个数据进行交换(目的:保持当前堆的结构)
pop出数据,将第一个数据进行向下调整
void pop()
{swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);
}
push数据
- 将数据进行尾插入,进行向上调整
void push(const T& x)
{_con.push_back(x);AdjustUp(_con.size() - 1);
}
priority_queue operators
- top数据,返回首个数据;
- 其他常见操作,采取容器适配器设计模式的操作
namespace mypriority_queue
{template<class T, class container = std::vector<T>,class compare = Less<T>>class priority_queue{public:const T& top(){return _con[0];}size_t szie(){return _con.size();}bool empty(){return _con.empty();}private:container _con;};}
源码(优先级队列)
namespace mypriority_queue
{template<class T>class Less{public:bool operator()(const T& a,const T& b){return a < b;}};template<class T>class Greater{public:bool operator()(const T& x, const T& y){return x > y;}};template<class T, class container = std::vector<T>,class compare = Less<T>>class priority_queue{void AdjustDown(size_t parent){compare com;size_t child = parent * 2 + 1;//if (child+1< _con.size() && _con[child] < _con[1+child])if (child + 1 < _con.size() && com(_con[child] ,_con[1 + child])){++child;}while (child <_con.size()){if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void AdjustUp(int child){compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent] , _con[child])){std::swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}public:template<class InputIterator>void push_back(InputIterator first, InputIterator last){while (first != last){_con.push_back(*first);++first;}//向下建堆for (int i = (_con.size() - 2) / 2; i >= 0; i--){AdjustDown(i);}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}const T& top(){return _con[0];}void push(const T& x){_con.push_back(x);AdjustUp(_con.size() - 1);}size_t szie(){return _con.size();}bool empty(){return _con.empty();}private:container _con;};}
向下建堆
for (int i = (_con.size() - 2) / 2; i >= 0; i–)
{
AdjustDown(i);
}
}
void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}const T& top(){return _con[0];}void push(const T& x){_con.push_back(x);AdjustUp(_con.size() - 1);}size_t szie(){return _con.size();}bool empty(){return _con.empty();}private:container _con;
};
}
相关文章:
【C++】优先级队列(容器适配器)
欢迎来到我的Blog,点击关注哦💕 前言 string vector list 这种线性结构是最基础的存储结构,C(STL)container很好的帮助我们数据存储的问题。 容器适配器 介绍 容器适配器是C标准模板库(STL)中…...
docker代理
Dockerd 代理 sudo mkdir -p /etc/systemd/system/docker.service.d sudo touch /etc/systemd/system/docker.service.d/proxy.confproxy.conf [Service] Environment"HTTP_PROXYproxy.example.com:8080/" Environment"HTTPS_PROXYproxy.example.com:8080/&qu…...
(四)activit5.23.0修复跟踪高亮显示BUG
一、先看bug 在 (三)springboot2.7.6集成activit5.23.0之流程跟踪高亮显示 末尾就发现高亮显示与预期不一样,比如上面的任务2前面的箭头没有高亮显示。 二、分析原因 具体分析步骤省略了,主要是ProcessInstanceHighlightsResour…...
AsyncTask
AsyncTask简介 AsyncTask 是 Android 提供的一个轻量级的异步任务类,它允许在后台线程中执行耗时操作(如网络请求、数据库操作等),并在操作完成后更新 UI。其设计初衷是为了简化后台任务的处理,特别是在不需要复杂并发…...
嵌入式面试知识点总结 -- FreeRTOS篇
一、堆栈溢出检测 问题: 问题一:FreeRTOS堆栈溢出检测的方法? 解答: 参看:FreeRTOS学习 – FreeRTOSConfig.h介绍 两种堆栈溢出检测方法: 方法1: 开启方法,configCHECK_FOR_STACK_OVERFLOW…...
【深度学习】注意力机制(Transformer)
注意力机制 1.基础概念 1.1 查询、键和值 在人类的注意力方式中,有自主性的与非自主性的注意力提示两种解释方式。所谓自主性注意力提示,就是人本身主动想要关注到的某样东西;非自主性提示则是基于环境中物体的突出性和易见性,…...
【MySQL】将一张表的某一个值赋值到另一张表中
场景 两张表可以通过某个字段关联起来,并且想要将其中一张表的某个值赋值到另一张表的某个字段中 实操 在MySQL中,要将一张表(我们称之为Table_A)的某个字段的值赋给另一张表(Table_B)的对应字段&#x…...
怎样确定局域网里面是否有MAC地址冲突
目录 MAC地址冲突的现象1. 网络连接不稳定2. 数据包丢失3. 网络性能下降4. 无法访问特定设备5. 网络诊断工具的异常结果6. 网络安全问题 确定MAC地址冲突的方法如何解决MAC地址冲突总结 MAC地址冲突 是指在同一局域网(LAN)中,两个或多个设备具…...
springboot 大学生兼职平台系统-计算机毕业设计源码05282
摘 要 在当代大学生活中,兼职工作已经成为了许多学生的重要组成部分。校园兼职现象的普遍性及其对大学生生活的影响不容忽视。然而,现有的校园兼职系统往往存在信息不对称、管理不规范等问题。因此,我们需要深入理解校园兼职现象,…...
CentOS linux安装nginx
下载nginx-1.21.3.tar.gz 及 nginx-upstream-fair-master.zip 上传nginx-upstream-fair-master至/app/server/nginx/modules/解压 cd /app/server/nginx/modules unzip nginx-upstream-fair-master.zip上传nginx压缩包至**/app/server/nginx/ **(根据自己需求而定…...
事务性邮件接口API如何集成以实现自动化?
事务性邮件接口API有哪些优势?邮件接口API集成方法? 通过集成事务性邮件接口API,企业可以实现邮件发送的自动化,提高效率,增强用户体验。AokSend将探讨如何集成事务性邮件接口API以实现自动化,并提供一些最…...
zabbix 监控软件
zabbix 监控软件 自带图形化界面,通过网页就可以监控所有服务器的状态 事件告警,邮箱通知(噩梦) 短信,电话。 zabbix是什么? web界面提供的分布式监控以及网络监控功能的开源的企业级软件解决方案 监…...
C语言随机数小游戏
目录 前言 一、游戏要求: 二、游戏实现 1.游戏界面 2.游戏主体 3.主函数 4.运行结果: 总结 前言 前面我们学到了C语言随机数的相关知识,我们今天用这个知识做一个有趣的小游戏,会有一点函数的知识,不过后面会…...
解决Ubuntu报“无法解析域名cn.archive.ubuntu.com“问题
今天在Ubuntu系统上,使用sudo apt update命令,进行更新时,弹出"无法解析域名 cn.archive.ubuntu.com"问题,如图(1)所示: 图(1) 弹出"无法解析域名 cn.archive.ubuntu.com" 错误 出现这种现象的原因…...
搭建pxe网络安装环境实现服务器自动部署
目录 配置 kickstart自动安装脚本 搭建dhcp服务 搭建pxe网络安装环境实现服务器自动部署 测试 配置 kickstart自动安装脚本 yum install system-config-kickstart #在rhel7做,rhel9要收费 system-config-kickstart #启动图形制作工具 vim …...
Go框架选战:Gin、Echo、Fiber的终极较量
Gin 优点: 高性能: 优化以处理高并发和低延迟请求。易于上手: 对于熟悉 Go 的开发者来说,API 设计直观,学习曲线低。社区支持强: 广泛使用,有大量第三方中间件和教程。 缺点: 相比于其他框架如 Echo,Gin缺乏内置的验证支持Gin…...
2024.8.08(python)
一、搭建python环境 1、检查是否安装python [rootpython ~]# yum list installed | grep python [rootpython ~]# yum list | grep python3 2、安装python3 [rootpython ~]# yum -y install python3 安装3.12可以使用源码安装 3、查看版本信息 [rootpython ~]# python3 --vers…...
RabbitMQ知识总结(基本原理+高级特性)
文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 基本原理 消息的可靠性投递 RabbitMQ 消息的投递路径为ÿ…...
字符串切割split
let obj {} let str "aa占比:17.48%,aa计费占比:0.00%" let arr str.split(,) // [aa占比:17.48%,aa计费占比:0.00%] arr.forEach(item > { let [key,value] item.split(:) obj[key] value }) console.log(obj) //{aa占比: 17.48%, aa计费占比: 0.00%} con…...
Python中的 `continue` 语句:掌握循环控制的艺术
Python中的 continue 语句:掌握循环控制的艺术 下滑即可查看博客内容 🌈 欢迎莅临我的个人主页 👈这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地!🎇 🎓 博主简介:985高校的普通…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...
