C++:Stack和Queue的模拟实现

news2024/11/20 4:23:31

                                                    创作不易,感谢三连! 

一、容器适配器

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

      就如同是电源适配器将不适用的交流电变得适用一样,模板 B 将不适合直接拿来用的模板 A 变得适用了,因此我们可以将模板 B 称为 B 适配器。 容器适配器也是同样的道理,简单的理解容器适配器,其就是将不适用的序列式容器(包括 vector、deque 和 list)变得适用。 容器适配器的底层实现和模板 A、B 的关系是完全相同的,即通过封装某个序列式容器,并重新组合该容器中包含的成员函数,使其满足某些特定场景的需要。

二、deque的简单了解

      我们知道,vector支持下标的随机访问,但是头部和中部插入删除效率低下,且需要频繁扩容,而list虽然任意位置插入删除高效,但是不支持随机访问,所以就有人在思考,能否找到一种数据结构可以替代他俩呢??于是就有了双端队列这个数据结构,但实际上双端队列并无法替代vector和list,并且后来成为了最适合stack和queue的底层容器,这就是典型的相当皇上没当成,却成了丫鬟。

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

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

     双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,重任落在了deque的迭代器身上。

下面我们进行总结:

我们可以看到:

1、与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是必vector高的。

2、与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。

3、但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list。

4、deque的应用并不多,但我们发现他的头插头删和尾插尾删的效率特别高,所以目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构。

5、还有第二个缺陷就是:

(1)如果我们假定buff每个数组大小一样大,那么随机访问的效率就会高,因为我们减掉该层的当前元素,然后/10可以跳层,再%10就可以跳到该层对应的位置,但是需要中间的插入和删除的话,那么为了维持每层的数组大小,就可能需要挪动一堆数据。

(2)如果我们假定每个buff数组的大小不一样大,那么如果中间的插入删除就不需要挪数据了,效率会提高,但是随机访问的效率就会变低了,因为不知道每层有多少元素,所以无法直接跳层,而是要一个个去遍历才能访问到某个元素。

     因此各有利弊不可兼得,在SGI版本下选择的是buff数组固定大小,所以他的迭代器设置得非常复杂。

那deque是如何借助其迭代器维护其假想连续的结构呢? 

三、Stack介绍

Stack文档介绍

1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其只能从容器的一端进行元素的插入与提取操作。

2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。

3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:
empty:判空操作
back:获取尾部元素操作
push_back:尾部插入元素操作
pop_back:尾部删除元素操作

4. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque。

四、Queue介绍

Queue文档介绍

1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。

2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。

3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
empty:检测队列是否为空
size:返回队列中有效元素的个数
front:返回队头元素的引用
back:返回队尾元素的引用
push_back:在队列尾部入队列
pop_front:在队列头部出队列

4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

五、为什么选择deque作为stack和queue的底层默认容器

      stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:

1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。

2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。

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

六、适配器模式下的stack模拟实现

using namespace std;
namespace cyx
{
	template<class T,class Container=deque<T>>// 可以用vectoe list deque作为适配器
	class stack
	{
	public:
		bool empty() const
		{
			return _con.empty();
		}

		size_t size() const
		{
			return _con.size();
		}
     
		const T& top() const
		{
			return _con.back();
		}

		T& top()
		{
			return _con.back();
		}

		void push(const T&val) 
		{
			_con.push_back(val);
		}

		void pop()
		{
			_con.pop_back();
		}

		void swap(stack<T> &s)
		{
			_con.swap(s._con);
		}

	private:
		Container _con;//适配器
	};

七、适配器模式下的queue模拟实现

namespace cyx
{
 template<class T,class Container=deque<T>>//该适配器可以用list deque  如果是用vector不太合适,因为不支持头删
 class queue
 {
 public:
	 bool empty() const
	 {
		 return _con.empty();
	 }

	 size_t size()
	 {
		 return _con.size();
	 }
  
	 T& front()
	 {
		 return _con.front();
	 }

	 const T& front() const 
	 {
		 return _con.front();
	 }

	 T& back()
	 {
		 return _con.back();
	 }

	 const T& back() const
	 {
		 return _con.back();
	 }

	 void push(const T&val)
	 {
		 _con.push_back(val);
	 }

	 void pop()
	 {
		 _con.pop_front();
	 }

	 void swap(queue<T> &q)
	 {
		 _con.swap(q._con);
	 }

 private:
		 Container _con;
 };

八、遍历的一般形式 

stack

queue

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

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

相关文章

STM32CubeMX学习笔记13 ---IIC总线

1、IIC 简介 IIC(Inter&#xff0d;Integrated Circuit)总线是一种由NXP&#xff08;原PHILIPS&#xff09;公司开发的两线式串行总线&#xff0c;用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信&#xff0c;在小数据量场合使用&#xff0c;传输距离短&…

《汇编语言》- 读书笔记 - 第17章-实验17 编写包含多个功能子程序的中断例程

《汇编语言》- 读书笔记 - 第17章-实验17 编写包含多个功能子程序的中断例程 逻辑扇区根据逻辑扇区号算出物理编号中断例程&#xff1a;通过逻辑扇区号对软盘进行读写 代码安装 int 7ch 测试程序效果 实现通过逻辑扇区号对软盘进行读写 逻辑扇区 计算公式: 逻辑扇区号 (面号*8…

【PCIe 链路训练】之均衡(equalization)

1、概述 这篇文章简单介绍一下PCIE phy的均衡原理和过程,USB phy,ethernet phy这些高速的串行serdes也有相同或者相似的结构。可以不用太关注其中的细节,等到debug的时候可以查询协议,但是需要了解这个故事讲的大概内容。整个equalization过程是controller和phy一起配合完成…

喜报|炼石免改造数据安全入选上海网安产业创新大会优秀案例

近日&#xff0c;上海网络安全产业创新大会隆重召开&#xff0c;上海普陀区委副书记、区长肖文高&#xff0c;上海市经济和信息化委员会总工程师葛东波出席并致辞&#xff0c;普陀区副区长肖立出席。大会以“产业赋能、生态打造”为主题&#xff0c;为发掘数据安全领域的优秀产…

【代码随想录算法训练营Day29】 491.递增子序列;46.全排列;47.全排列 II

文章目录 ❇️Day 29 第七章 回溯算法 part05✴️今日内容❇️491.递增子序列自己的思路随想录思路自己的代码 ❇️46.全排列思路代码流程 ❇️47.全排列 II思路代码 ❇️Day 29 第七章 回溯算法 part05 ✴️今日内容 491.递增子序列46.全排列47.全排列 II ❇️491.递增子序…

低压MOS在步进电机驱动器上的应用-REASUNOS瑞森半导体

一、前言 步进电机驱动器是一种用于控制步进电机运动的装置&#xff0c;它是将控制信号转换成步进电机可以识别的控制电压或电流的电路。它在工业自动化领域有着广泛的应用&#xff0c;如机器人、印刷机、木工机床、喷绘机等。步进电机驱动器的组成结构主要由以下部分&#xf…

《C缺陷和陷阱》-笔记

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 文章目录 前言 一、理解函数声明 1.(*(void(*)( ))0)( ); 2.signal 函数接受两个参数&#xff1a; 3.使用typedef 简化函数声明&#xff1a; 二、运算符的优先级…

面试经典150题【61-70】

文章目录 面试经典150题【61-70】61.旋转链表86.分隔链表104. 二叉树的最大深度100.相同的树226.翻转二叉树101.对称二叉树105.从前序与中序遍历序列构造二叉树106.从后序和中序遍历序列构造二叉树117.填充每个节点的下一个右侧节点指针II114.二叉树展开为链表 面试经典150题【…

修复 因 fstab 中UUID 错误导致系统无法正常工作的问题

操作系统&#xff1a; PVE 8.0 /debian 12 &#xff08;bookworm&#xff09; 问题症状&#xff1a;可以正常启动进入系统&#xff0c;但是系统盘以只读方式挂载 问题原因&#xff1a;/etc/fstab 中引导区的UUID 被错误修改导致 解决方法&#xff1a; 重启系统&#xff0c;在…

QT:用opencv的KNN识别图片中的LED数字(一)

前言 一款功能测试的软件demo,使用了QT作为界面,主要使用了opencv的KNN识别,使用gstreamer作为管道,用来打开图片。后期会写一篇打开摄像头实时识别的文章。 (正在写,未完成,稍候) 效果一预览: 效果二预览: 效果三预览: 正在写。。。 设计思路 1. 软件UI设…

吴恩达深度学习笔记:深度学习引言1.1-1.5

目录 第一门课&#xff1a;神经网络和深度学习 (Neural Networks and Deep Learning)第一周&#xff1a;深度学习引言(Introduction to Deep Learning)1.1 欢迎(Welcome)1.2 什么是神经网络&#xff1f;(What is a Neural Network)1.3 神经网络的监督学习(Supervised Learning …

【C++】C++模板基础知识篇

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 泛型编程2. 函数模板2.1 函数模板概念2.2 函数模板格式2.3 函数模板的原理2.4 函数模板的实例化2.5 模板参数的匹配原则 3. 类模板3.1 类模板的定义格式3.2 类模板的实例化…

Trans论文复现:考虑源荷不平衡性的微电网鲁棒定价方法程序代码!

适用平台&#xff1a;MatlabYalmipCplex/Gurobi 程序针对目前微电网中高比例新能源发电的波动性和间歇性&#xff0c;提出了考虑源荷不平衡特性的微电网鲁棒定价方法&#xff0c;综合考虑电力市场边际收益和边际成本&#xff0c;利用价格波动来平衡电源和负荷。程序算例丰富、注…

腾讯云轻量 2核2G4M新用户首购活动,99续费同价来了!!

阿里云199一年续费同价&#xff0c;腾讯云99一年续费同价&#xff0c;平台卷起来&#xff0c;对用户的角度来说&#xff0c;真的是香麻了~ 腾讯云新春采购节&#xff0c;2核2G4兆的基础配置&#xff0c;新官方直接放大招&#xff0c;99一年&#xff0c;活动期间内&#xff0c;…

EXSI create datastore

文章目录 1. 简介2. 清空磁盘3. 删除表4. 创建database 1. 简介 在 ESXi 环境中创建数据存储(Datastore)的步骤如下: 登录 vSphere Web Client 打开 Web 浏览器,输入 ESXi 主机或 vCenter Server 的 IP 地址,使用有权限的账户登录。 在 ESXi 环境中创建数据存储(Datastore)…

二、TensorFlow结构分析(4)

TF数据流图图与TensorBoard会话张量Tensor变量OP高级API 目录 1、变量 2、高级API 1、变量 2、高级API

【Kafka系列 07】Kafka 如何保证消息不丢失

一、Kafka 消息不丢失的边界 一直以来&#xff0c;很多人对于 Kafka 丢失消息这件事情都有着自己的理解&#xff0c;因而也就有着自己的解决之道。在讨论具体的应对方法之前&#xff0c;我觉得我们首先要明确&#xff0c;在 Kafka 的世界里什么才算是消息丢失&#xff0c;或者…

华为云开年采购季Web及移动App上云体验,助力软件行业创新发展

随着云化、智能化浪潮的进一步深入&#xff0c;越来越多的应用软件开发商选择将核心产品从本地IDC机房搬迁到公有云上。但同时&#xff0c;软件开发商们也非常在意公有云厂商的可靠性与安全性&#xff0c;希望能够选择一家更加稳定可靠的云服务商&#xff0c;确保自身业务的连续…

02极简LLM逻辑与PyTorch快速入门

文章目录 02极简LLM逻辑与PyTorch快速入门极简LLM逻辑PyTorch环境安装&#xff08;重要&#xff0c;不难&#xff09;PyTorch 主要概念Tensors张量张量常见的形式&#xff1a;scalar、vector、matrix、n-dimensinal张量初始化张量参数&#xff1a;shape、datatype、device张量运…

从huggingface下载模型像本地加载但是UnicodeDecodeError

我自己是在Linux下出现了这个问题 原文&#xff1a;https://github.com/huggingface/transformers/issues/13674 The path for the AutoModel should be to a directory pointing to a pytorch_model.bin and to a config.json. Since you’re pointing to the .bin file dire…