【C++进阶】STL容器--stack和queue深度剖析优先队列适配器原理

目录

前言

 1. 容器的使用

1.1 stack

1.2 queue

 2. 什么是适配器

3. stack&&queue底层实现

4. deque的简单介绍

4.1 deque的缺陷

5. priority_queue

 思考

 6. priority_queue的实现


前言

        栈和队列在C语言中大家都有所了解,C语言的栈和队列都是我们手动去实现,而C++中的栈和队列不同,它们的内部并不是自己实现的,而是适配器模式,它们都是容器适配器;本文将会围绕栈和队列来介绍适配器的原理;

在这里插入图片描述

 1. 容器的使用

         在深入了解STL容器之前,我们先来看看stack和queue库里边提供了哪些接口;

1.1 stack

栈的功能接口及简介

1.2 queue

队列的功能接口及简介

 从这些接口及功能上我们发现,栈和队列它们都不支持遍历;在刷题时,栈的应用相较来说也比较多;

下边是一些练习题目,可以练习一下:

 最小栈(力扣)

 栈的压入和弹出序列(牛客)

 逆波兰表达式求值(力扣)

 二叉树的层序遍历(力扣)

 二叉树的层序遍历使用队列解决

 2. 什么是适配器

        适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口

 它的核心其实就是复用,举个日常生活中的例子,充电器的适配器:

3. stack&&queue底层实现

         开始时提到stack和queue都是容器适配器,那到底什么是容器适配器?我们先来看看它的底层声明或许就会明白了:

stack:

 queue:

         它们用到了两个模板参数,一个是存储的数据类型,一个就是底层实现的容器;它们默认使用的都是deque(双端队列);

 那到底什么是容器适配器?容器适配器即将特定容器类封装作为其底层容器类

 了解完这些我们可以上手来实现一下:

我们可以复用其他容器的接口来实现封装,为了和库里尽量保持一致,我们也使用双模板参数:

实现代码如下:

template<class T, class container = deque<T>>
class stack
{
public:void push(const T& x){return _con.push_back(x);}void pop(){return _con.pop_back();}T& top(){return _con.back();}bool empty(){return _con.empty();}size_t size(){return _con.szie();}private:container _con;
};

队列

template<class T, class container = deque<T>>
class queue
{
public:void push(const T& x){return _con.push_back(x);}void pop(){return _con.pop_front();}T& front(){return _con.front();}T& black(){return _con.black();}bool empty(){return _con.empty();}size_t size(){return _con.szie();}private:container _con;
};

 在调用时我们也可以控制它底层使用的容器

queue<int, list<int>> q1;
stack<int, vector<int>> st;

我们在用STL库里的stack和queue时也没有传参啊?

这是因为库里边给Container(容器)一个缺省参数,默认使用的是deque(双端队列)

4. deque的简单介绍

双端队列名字中带有队列,但它其实并不是队列;

队列要求尾进头出,而双端队列可以双向进出;

 简介

         deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高,并且支持随机访问;

         双端队列同时具体它们的优点,在功能上deque可以算的上是list和vector的结合版;

 它的使用和list、vector的使用方法基本一致,但它的底层相较于它们却非常复杂;

 deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成,实际deque类似于一个动态的二维数组;

 数组里边存的是指针,指针指向的是一个个的buff数组,这个存放指针的数组也叫作中控数组

 中控满了进行扩容时,会直接开一块新空间,将内容拷贝过去(拷贝指针代价较小)

4.1 deque的缺陷

         与vector相比,deque的优势是:头插和头删时,不需要挪动数据,效率很高,扩容时也不需要大量的挪动数据(只需要挪作指针即可);

         与list相比,其底层是连续空间,空间利用率比较高;

         它的各个属性都还可以可谓是 “ 六边形战士 ”,但是它的各个属性都不是最顶尖的;它的遍历效率没有vector高,中间插入删除操作没有list效率高;所以它主要作为stack和queue的底层容器;

主要原因有两个:

  1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作;
  2. 在stack中需要扩容时,deque比vector的效率高(扩容时不需要搬移大量数据),在queue中空间利用率较高,不需要频繁开空间;

5. priority_queue

         优先队列它也是一种容器适配器,默认情况下priority_queue类实例化时使用的是vector;

 那优先队列到底是什么?本质是其实就是堆,在默认情况下是大堆,通过我们所传的模板参数进行控制;

 如果要创建小堆,将第三个模板参数换成greater比较方式

vector<int> v = { 3,1,5,6,4,0 };
priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());

 思考

 实现优先队列之前思考一个问题,优先队列需不需要实现:构造函数、拷贝构造、析构函数 ?

         不需要,优先队列是一种容器适配器,它是通过其他容器封装来的,使用时生成默认的构造函数、拷贝构造、析构函数;它们又会去调用底层容器的构造函数、拷贝构造、析构函数;

 6. priority_queue的实现

         堆的相关内容前边已经介绍过了,详细介绍可见:二叉树的顺序存储(堆)

   priority_queue基本框架如下:

template<class T, class container = vector<T>>
class priority_queue
{
public:private:container _con;
};

堆的核心内容就在于向上调整和向下调整(默认大堆),实现代码如下:

 向上调整:

void adjust_up(int child)
{size_t parent = (child - 1) / 2;while (child > 0){if (_con[parent] < _con[child]){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

 向下调整:

void adjust_down(int parent)
{size_t child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && _con[child] < _con[child + 1]){child++;}if (_con[parent] < _con[child]){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}

入堆和出堆以及其他功能的实现

void push(const T& x)
{_con.push_back(x);adjust_up(_con.size() - 1);
}void pop()
{swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);
}bool empty()
{return _con.empty();
}T& top()
{return _con[0];
}
size_t size()
{return _con.size();
}

         以上便是priority_queue的基本实现;细心的朋友可能会发现,我们实现的与库里的有些不同,在调整大堆小堆时也不能通过传参控制,对于当前实现的priority_queue我们还需要做进一步的封装,达到这些需求需要了解模板相关的其他内容;下期我将会再次深入探讨模板——模板进阶;

 以上便是本文的全部内容,希望可以对你有所帮助,感谢阅读!

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

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

相关文章

js:通过input标签或Drag拖拽文件实现浏览器文件上传获取File文件对象

文档 https://developer.mozilla.org/zh-CN/docs/Web/API/Filehttps://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/drag_event 通过读取文件可以获取File对象的信息 lastModified: 1707210706000 lastModifiedDate: Tue Feb 06 2024 17:11:46 GMT0800 (中国标准…

NeurIPS 2023 Spotlight | VoxDet:基于3D体素表征学习的新颖实例检测器

本文提出基于3D体素表征学习的新颖实例检测器VoxDet。给定目标实例的多视图&#xff0c;VoxDet建立该实例的三维体素表征。在更加杂乱的测试图片上&#xff0c;VoxDet使用体素匹配算法检测目标实例。实验表明&#xff0c;VoxDet中的三维体素表征与匹配比多种二维特征与匹配要更…

Linux进程 ----- 信号处理

前言 从信号产生到信号保存&#xff0c;中间经历了很多&#xff0c;当操作系统准备对信号进行处理时&#xff0c;还需要判断时机是否 “合适”&#xff0c;在绝大多数情况下&#xff0c;只有在 “合适” 的时机才能处理信号&#xff0c;即调用信号的执行动作。 一、信号的处理…

linux系统---nginx基础

目录 一、Nginx的概念 二、Nginx常用功能 1、HTTP(正向)代理&#xff0c;反向代理 1.1正向代理 1.2 反向代理 2、负载均衡 2.1 轮询法&#xff08;默认方法&#xff09; 2.2 weight权重模式&#xff08;加权轮询&#xff09; 2.3 ip_hash 3、web缓存 三、基础特性 四…

基于SpringBoot+Apache ECharts的前后端分离外卖项目-苍穹外卖(十八)

数据展示 1. Apache ECharts1.1 介绍1.2 入门案例 2. 营业额统计2.1 需求分析和设计2.1.1 产品原型2.1.2 接口设计 2.2 代码开发2.2.1 VO设计2.2.2 Controller层2.2.3 Service层接口2.2.4 Service层实现类2.2.5 Mapper层 2.3 功能测试 3. 用户统计3.1 需求分析和设计3.1.1 产品…

【人脸朝向识别与分类预测】基于PNN神经网络

课题名称&#xff1a;基于PNN神经网络的人脸朝向识别分类 版本日期&#xff1a;2024-02-20 运行方式&#xff1a;直接运行PNN0503.m文件 代码获取方式&#xff1a;私信博主或 QQ:491052175 模型描述&#xff1a; 采集到一组人脸朝向不同角度时的图像&#xff0c;图像来自不…

【Spring】事务总结

目录 1. 什么是事务&#xff1f; 2. 事务的特性&#xff08;ACID&#xff09;了解么? 3. 详谈 Spring 对事务的支持 3.1. Spring 支持两种方式的事务管理 1).编程式事务管理 2)声明式事务管理 3.2. Spring 事务管理接口介绍 3.2.1. PlatformTransactionManager:事务管理…

投资黄金在哪里买比较好?

黄金&#xff0c;作为一种传统的避险资产&#xff0c;历来受到投资者的青睐。在全球经济波动的大背景下&#xff0c;黄金的价值愈发凸显。那么&#xff0c;投资黄金在哪里买比较好呢&#xff1f;本文将重点探讨在香港黄金平台投资黄金的优势&#xff0c;并以金田金业为例&#…

Powershell中conda init失效、无法使用conda activate的问题

起因 近期折腾了一下Windows Terminal&#xff0c;安装配置了Powershell 7.3&#xff0c;然后发现conda activate在Powershell中用不了了&#xff0c;conda init powershell不起作用&#xff0c;conda init cmd.exe没有问题 分析 因为powershell的profile.ps1文件路径中存在…

ELK 简介安装

1、概念介绍 日志介绍 日志就是程序产生的&#xff0c;遵循一定格式&#xff08;通常包含时间戳&#xff09;的文本数据。 通常日志由服务器生成&#xff0c;输出到不同的文件中&#xff0c;一般会有系统日志、 应用日志、安全日志。这些日志分散地存储在不同的机器上。 日志…

网络层的DDoS攻击与应用层的DDoS攻击之间的区别

DDoS攻击&#xff08;即“分布是拒绝服务攻击”&#xff09;&#xff0c;是基于DoS的特殊形式的拒绝服务攻击&#xff0c;是一种分布式、协作的大规模攻击方式&#xff0c;主要瞄准一些企业或政府部门的网站发起攻击。根据攻击原理和方式的区别&#xff0c;可以把DDoS攻击分为两…

The Grapes NFT 概览与数据分析

作者&#xff1a;stellafootprint.network 编译&#xff1a;cicifootprint.network 数据源&#xff1a;The Grapes NFT Collection Dashboard The Grapes 是一个有趣且具有吸引力的 NFT 收藏集合&#xff0c;包含 3,333 个精心制作的 NFT。这个 NFT 项目会在 2024 年再创高…

linux僵尸进程

僵尸进程&#xff08;Zombie Process&#xff09;是指在一个进程终止时&#xff0c;其父进程尚未调用wait()或waitpid()函数来获取该进程的终止状态信息&#xff0c;导致进程的资源&#xff08;如进程表中的记录&#xff09;仍然保留在系统中的一种状态。 当一个进程结束时&am…

GO数组解密:从基础到高阶全解

在本文中&#xff0c;我们深入探讨了Go语言中数组的各个方面。从基础概念、常规操作&#xff0c;到高级技巧和特殊操作&#xff0c;我们通过清晰的解释和具体的Go代码示例为读者提供了全面的指南。无论您是初学者还是经验丰富的开发者&#xff0c;这篇文章都将助您更深入地理解…

java使用Swagger文档报错“java.lang.NullPointerException: null”

java使用Swagger文档报错 一、问题二、解决1、报错2、源码3、方法 一、问题 java项目引入Swagger文档&#xff0c;后期因为一些原因导致Swagger文档不能使用&#xff0c;但是不影响项目运行和正常使用&#xff0c;但每次启动都会报错。 原因有可能是&#xff1a; 1、一个实体类…

【HMAC-SHA1算法以及工作原理】

曾梦想执剑走天涯&#xff0c;我是程序猿【AK】 目录 简述概要知识图谱总结 简述概要 连接HMAC-SHA1工作原理以及工具代码 知识图谱 HMAC&#xff08;Hash-based Message Authentication Code&#xff0c;基于散列的消息认证码&#xff09;是一种结合了密钥和消息的认证方法…

刚拿到的《HarmonyOS应用开发者高级认证》,全网整理的题目,将近300题,100%通过

刚拿到《HarmonyOS应用开发者高级认证》&#xff0c;现在把题目和答案分享一下&#xff0c;这些题目是我根据其他网站整理的&#xff0c;宁滥勿缺&#xff0c;有个别题目是重复的&#xff0c;抽半天时间看一下&#xff0c;应该是稳过的。当然建议还是先跟着文档学一下鸿蒙或者看…

Centos 7.5 上nginx设置开机自启动

nginx的安装目录 &#xff1a; /usr/local/nginx 一、没有设置开机自启动前&#xff0c;需要执行/usr/local/nginx/sbin/nginx 启动 二、接下来&#xff0c;我们设置开机自启动&#xff0c;就不用手动启动nginx了 1、cd /usr/lib/systemd/system/ 2、vi nginx.service [un…

如何在Win系统搭建Oracle数据库并实现远程访问【内网穿透】

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle&#xff0c;是甲骨文公司的一款关系…

【深入理解设计模式】适配器设计模式

适配器设计模式 适配器设计模式是一种结构型设计模式&#xff0c;用于将一个类的接口转换成客户端所期望的另一个接口&#xff0c;从而使得原本由于接口不兼容而不能一起工作的类能够一起工作。适配器模式通常用于以下场景&#xff1a; 现有接口与需求不匹配&#xff1a;当需要…