【C++】STL之适配器---用deque实现栈和队列

目录

前言

一、deque

 1、deque 的原理介绍

 2、deque 的底层结构

 3、deque 的迭代器

 4、deque 的优缺点

  4.1、优点

  4.2、缺点

二、stack 的介绍和使用

 1、stack 的介绍

 2、stack 的使用

 3、stack 的模拟实现

三、queue 的介绍和使用

 1、queue 的介绍 

 2、queue 的使用

 3、queue 的模拟实现


前言

  容器适配器,按字面意思理解的话,就是用来对一个容器进行匹配的。在C++STL中,容器有:vector,list,deque,map,set等。而在C++STL中不把stack和queue纳入容器的范围而是纳入容器适配器的范围是因为:

  stack和queue没有下标随机访问等操作,只有普通的pop_front,push_back,pop_back()等操作,而这些函数在其他容器中完全可以有,栈和队列的实现完全可以将其他容器的操作进行复用,这就是stack和queue作为容器适配器的原因。

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

一、deque

 1、deque 的原理介绍

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

 2、deque 的底层结构

  deque 的底层结构其实并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际 deque 类似于一个动态的二维数组,其结构示意图如下:

 3、deque 的迭代器

  双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落 在了deque的迭代器身上,因此 deque 的迭代器设计就比较复杂,如下图所示:

 4、deque 的优缺点

  4.1、优点

  • 具有 vector 的优点 ---支持随机访问、缓存命中率较高、尾部插入删除数据效率高;
  • 同时具有 list 的优点 --- 空间浪费少、头部插入插入数据效率高;

  4.2、缺点

  • deque 的随机访问效率较低 --- 需要先通过中控数据找到对应的buffer数组,再找到具体的位置 (假设偏移量为 i,需先 i/10 得到位于第几个buffer数组,再 i%10 得到 buffer 数组中的具体位置),即 deque 随机访问时一次跳过一个buffer数组,需要跳多次才能准确定位,其效率比 list 高了不少,但比 vector 也低了不少;
  • deque 在中部插入删除数据的效率是比较低的 --- 需要挪动数据,但不一定后续 buffe 数组中的数据全部挪动,可以控制只挪一部分,即中间插入删除数据的效率高于 vector,但是低于 list。

 所以综上分析, deque 结合了 vector 和 list 的优缺点,看似很完美,但是它单方面的性能是不如 vector 或者 list 的,因此 deque 在实际应用中使用的非常少。

STL 中选择 deque 作为 stack 和 queue 默认适配容器的原因:

  • stack 和 queue 不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
  • 在 stack 中元素增长时,deque 比 vector 的效率高(扩容时不需要搬移大量数据);queue 中的元素增长时,deque不仅效率高,而且内存使用率高。

结合了deque的优点,而完美的避开了其缺陷。

  deque 特别适合需要大量进行头插和尾部数据的插入删除、偶尔随机访问、偶尔中部插入删除的场景;不太适合需要大量进行随机访问与中部数据插入删除的场景,特别是排序。

二、stack 的介绍和使用

 1、stack 的介绍

  1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。
  2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定 的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
  3. stack 的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:empty:判空操作 back:获取尾部元素操作 push_back:尾部插入元素操作 pop_back:尾部删除元素操作;
  4. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器, 默认情况下使用deque。

 2、stack 的使用

函数说明接口说明
stack()构造空的栈
empty()检测 stack 是否为空
size()返回 stack 中元素的个数
top()返回栈顶元素的引用
push()将元素 val 压入 stack 中
pop()将 stack 中尾部的元素弹出

下面是栈的使用操作: 

int main()
{//构造空栈stack<int> s;//元素入栈s.push(1);s.push(2);//获取栈中元素个数int Size = s.size();cout << Size << endl;//获取栈顶元素的引用int sTop = s.top();cout << sTop << endl;//元素出栈s.pop();sTop = s.top();cout << sTop << endl;//判断栈是否为空cout << s.empty();return 0;
}

 3、stack 的模拟实现

  我们在这里为栈模板定义了两个模板参数:是栈中存储的元素的类型Container 是栈模板使用的底层结构Container 的默认值是 vector,如果你想要用别的,可以在这里进行设置。我就可以将适配器作为类的第二个模板参数,然后通过传递不同的适配容器来实现栈了:

//stack.h
template<class T, class Container>
class stack 
{//...
};
//test.cpp
void test_stack() 
{stack<int, vector<int>> st1;stack<int, list<int>> st2;
}

vector 和 list 都可以作为 stack 的适配容器,我们可以通过给定不同的第二个模板参数来使用不同的容器适配 stack;

 经过前期的学习,显然更适合作为 stack 的适配容器,那么我们可以还可以将 vector 设置为 stack 的默认适配容器:

//stack.h
template<class T, class Container = vector<T>>
class stack 
{//...
};
//test.cpp
void test_stack() 
{//默认使用vector做适配容器stack<int> st1;  //使用其他容器做适配容器需要显式指定stack<int, list<int>> st2;  
}

 有了适配容器之后,我们就可以更容易的通过调用适配容器的接口来实现 stack 的接口了。

namespace xx
{//适配器模式/配接器template <class T, class Container = deque<T>>class stack{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}const T& top(){return _con.back();}bool size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};void test_stack(){//stack<int,vector<int>> st;//数组栈stack<int, list<int>> st;//链表栈st.push(1);st.push(2);st.push(3);st.push(4);while (!st.empty()){cout << st.top() << " ";st.pop();}cout << endl;}
}

stack 可以使用 vector 或者 list 来实现,效率相当。插入数据就相当于尾插,删除栈顶元素就相当于尾删。

三、queue 的介绍和使用

 1、queue 的介绍 

  1. 队列是一种容器适配器,专门用于在 FIFO 上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。
  2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue 提供一组特定的 成员函数来访问其元素。元素从队尾入队列,从队头出队列。
  3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作: empty:检测队列是否为空 ; size:返回队列中有效元素的个数; front:返回队头元素的引用;back:返回队尾元素的引用;push_back:在队列尾部入队列;pop_front:在队列头部出队列;
  4. 标准容器类 deque 和 list 满足了这些要求。默认情况下,如果没有为 queue 实例化指定容器类,则使用标准容器 deque。

 2、queue 的使用

函数声明接口说明
queue()构造空的队列
empty()检测队列是否为空,是返回 true,否则返回 false
size()返回队列中有效元素的个数
front()返回队头元素的引用
back()返回队尾元素的引用
push()在队尾将元素 val 入队列
pop()将队头元素出队列

下面是队列的使用操作:

int main() 
{//构造空队列queue<int> q;//元素入队q.push(1);q.push(2);//返回有效元素个数int size = q.size();cout << size << endl;//检查队列是否为空cout << q.empty() << endl;//获取队头元素的引用int front = q.front();cout << front << endl;//获取队尾元素的引用 int back = q.back();cout << back << endl;//队头元素出队q.pop();return 0;
}

 3、queue 的模拟实现

  它的模拟实现过程和 stack 类似,vector 和 list 都可以作为 queue 的适配容器,但是由于 queue 需要大量在头部删除数据,所以使用 deque 作为 queue 的默认适配容器,那么 queue 模拟实现的代码如下:

namespace xx
{template <class T, class Container = deque<T>>class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}const T& front(){return _con.front();}const T& back(){return _con.back();}bool size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};void test_queue(){queue<int> q;q.push(1);q.push(2);q.push(3);q.push(4);while (!q.empty()){cout << q.front() << " ";q.pop();}cout << endl;}
}


本文要是有不足的地方,欢迎大家在下面评论,我会在第一时间更正。

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

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

相关文章

RabbitMQ实现秒杀场景示例

本文章通过MQ队列来实现秒杀场景 整体的设计如下图&#xff0c;整个流程中对于发送发MQ失败和发送到死信队列的数据未做后续处理 1、首先先创建MQ的配置文件 Configuration public class RabbitConfig {public static final String DEAD_LETTER_EXCHANGE "deadLetterE…

Python爬虫在Web应用自动化测试中的应用

在Web应用开发过程中&#xff0c;自动化测试是确保应用质量和稳定性的重要环节。本文将介绍如何使用Python爬虫与自动化测试技术相结合&#xff0c;实现对Web应用进行自动化测试的方法和步骤。通过这种结合&#xff0c;我们可以提高测试效率、减少人力成本&#xff0c;并确保应…

2023-09-25 LeetCode每日一题(LFU 缓存)

2023-09-25每日一题 一、题目编号 460. LFU 缓存二、题目链接 点击跳转到题目位置 三、题目描述 请你为 最不经常使用&#xff08;LFU&#xff09;缓存算法设计并实现数据结构。 实现 LFUCache 类&#xff1a; LFUCache(int capacity) - 用数据结构的容量 capacity 初始…

设计模式之解释器模式

文章目录 四则运算问题传统方案解决四则运算问题分析解释器模式基本介绍解释器模式的原理类图解释器模式来实现四则解释器模式的注意事项和细节 四则运算问题 通过解释器模式来实现四则运算&#xff0c;如计算 ab-c 的值&#xff0c;具体要求 先输入表达式的形式&#xff0c;比…

如何访问TDH中Inceptor 底层的元数据库TxSQL

如何访问TDH中Inceptor 底层的元数据库TxSQL 1 Inceptor概述 在大数据生态系统中&#xff0c;HIVE是离线数据仓库事实上的标准&#xff0c;绝大多数的大数据分析型系统或数据仓库系统&#xff0c;都是基于HIVE来构建的。 在星环的大数据平台TDH中&#xff0c;在功能上对应开…

基于物联网的农村地区智能微电网系统(Simulink)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

uniapp webview实现双向通信

需求&#xff1a;uniapp webview嵌套一个h5 实现双向通信 uniapp 代码 <template><view><web-view src"http://192.168.3.150:9003/" message"onMessage"></web-view></view> </template><script>export defau…

Mysql主从数据恢复随笔

目录 1.使用pt-table-checksum插件安装方式如下 2.在主节点执行检查数据同步情况 3.同步检查出现的问题 3.1没有sock文件 3.2 Authentication plugin ‘sha256_password’ cannot be loaded: /usr/lib64/mysql/plugin/sha256_password.so: 无法打开共享对象文件: 没有那个文…

【办公自动化】使用Python一键往Word文档的表格中填写数据(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

vSAN数据恢复-vSAN架构下虚拟机磁盘组件出现问题的数据恢复案例

vsan数据恢复环境&#xff1a; 一套VMware vSAN超融合基础架构&#xff0c;全闪存&#xff0c;开启压缩重删。共11台服务器节点。每台服务器节点上配置1块PCIE固态硬盘和8-10块SSD固态硬盘。 每个服务器节点上创建1个磁盘组&#xff0c;每个磁盘组将1个PCIE固态硬盘识别为2个硬…

YOLOv8快速复现 官网版本 ultralytics

YOLOV8环境安装教程.&#xff1a;https://www.bilibili.com/video/BV1dG4y1c7dH/ YOLOV8保姆级教学视频:https://www.bilibili.com/video/BV1qd4y1L7aX/ b站视频&#xff1a;https://www.bilibili.com/video/BV12p4y1c7UY/ 1 平台搭建YOLOv8 平台&#xff1a;https://www.a…

使用Python进行员工流失分析

员工流失分析是指分析离开公司、企业的员工的行为&#xff0c;并将他们与公司中的现有员工进行比较。它有助于找出哪些员工可能很快离开。所以&#xff0c;如果你想学习如何分析员工流失&#xff0c;这篇文章适合你。本文中&#xff0c;将带您完成使用Python进行员工流失分析的…

【李沐深度学习笔记】基础优化方法

课程地址和说明 基础优化方法p2 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 基础优化方法 在讲具体的线性回归实现之前&#xff0c;要先讲一下基础的优化模型的方法 梯度下降 当模型没有显示解&#xff08…

华为孟晚舟:从最惨千金 到最强战士

作者&#xff1a;积溪 简评&#xff1a;华为25号开发布会&#xff0c;有何深意&#xff1f;从最惨千金到最强战士&#xff0c;孟晚舟和华为都回来了 #华为发布会 #孟晚舟 #任正非 #华为 华为发布会 在打谁的脸&#xff1f; 苹果只是前菜 今天才是正餐 两年前的今天 华为…

数据结构 | 树

树 树是n&#xff08;n>0&#xff09;个结点的有限集。当n 0时&#xff0c;称为空树。在任意一棵非空树中应满足&#xff1a; 有且仅有一个特定的称为根的结点。当n>1时&#xff0c;其余节点可分为m&#xff08;m>0&#xff09;个互不相交的有限集T1,T2,…,Tm&#…

git_回退到上一次commit与pull

git 回退到上个版本 rollback 回滚 git reset HEAD&#xff0c; git 回退到上一版本

SpringCloud 学习(一)简介和环境搭建

1. 简介 1.1 SpringCloud SpringCloud 基于 SpringBoot 提供了一套微服务解决方案&#xff0c;包括服务注册与发现&#xff0c;配置中心&#xff0c;全链路监控&#xff0c;服务网关&#xff0c;负载均衡&#xff0c;熔断器等组件&#xff0c;除了 NetFlix 的开源组件做高度抽…

SpringMVC 学习(一)Servlet

1. Hello Servlet (1) 创建父工程 删除src文件夹 引入一些基本的依赖 <!--依赖--> <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test<…

【KMP算法】C++

KMP算法的原理是通过构建部分匹配表&#xff0c;来利用已经匹配过的信息&#xff0c;避免不必要的回溯。部分匹配表是一个长度与模式字符串相等的数组&#xff0c;用于记录在每个位置上的最长公共前后缀的长度。 这样图片完全表达了KMP算法的核心思想&#xff0c;出处来自添加链…

ruoyi-nbcio项目增加右上角的消息提醒

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 因为以后流程的通知需要提醒&#xff0c;所以右上角需要增加消息提醒。 1、增加右上角的按钮与信息 <div class"right-menu"><templat…