【C++】STL中stack和queue(适配器版)的模拟实现

news2024/12/26 1:34:49

前言:在此之前我们讲到了stack和queue还有deque的常见的使用方法,并且也在数据结构的时候用C语言去实现过栈和队列,今天我们将进一步的用C++去模拟实现stack和queue

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:高质量C++学习 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
在这里插入图片描述


目录标题

  • 什么是适配器
  • Stack的模拟实现
    • Stack的基本结构
    • 常见函数的模拟实现
      • 入栈 - push(const T& x)
      • 出栈- pop()
      • 获取栈顶元素 - const T& top()
      • 栈中的元素个数 - size_t size()
      • 判断栈是否为空
    • 整体代码:
  • Queue的模拟实现
    • Queue的基本结构
    • 常见函数的模拟实现
      • 入队列- push(const T& x)
      • 出队列- pop()
      • 获取队头元素- const T& front()
      • 获取队尾元素- const T& back()
      • 获取队列元素个数 - size_t size()
      • 判断队列是否为空 - bool empty()
    • 整体代码


在讲stack和queue的模拟实现之前我们需要提到一个概念:适配器

什么是适配器

适配器是一种设计模式,也是一种编程工具,用于将一个类的接口转换成另一个类的接口。适配器模式允许不兼容的类之间能够协同工作。

在C++中,适配器是指通过改变容器的接口使其适用于不同的需求。适配器可以封装容器,以提供一种更简单、更有限的功能接口,或者可以通过改变容器的工作方式来满足特定的需求。

在STL(标准模板库)中,适配器包括以下几种:

  1. 迭代器适配器:用于改变迭代器的行为,如reverse_iterator适配器用于反向遍历一个容器。
  2. 容器适配器:用于改变容器的接口,如stack适配器用于实现堆栈功能。
  3. 函数适配器:用于改变函数的行为,如bind适配器用于绑定函数和参数,生成新的函数对象。

适配器模式是一种重要的设计模式,它提供了一种解决兼容性问题的方式,并且可以使代码更加灵活和可复用。在C++中,STL的适配器提供了方便的工具和容器,使开发者能够更好地处理不同的需求和场景。
在这里插入图片描述


Stack的模拟实现

Stack的基本结构

这里很多人就会说,我们在C语言实现栈的时候就是像下面这么写的呐,就和实现vector一样的方式去实现stack不就行了嘛?如果是要用这样的方式去实现,那么博主今天就不会提到适配器这个概念了。
在这里插入图片描述


代码思路: 既然我们使用适配器来帮助我们来实现stack,那就是说你这个容器适配器的功能要满足我们stack所需要的入栈、出栈、获取栈顶元素、判断是否为空等等。

namespace bit 
{
	//这里我们通过模板来灵活的选择底层的容器适配器,只需要适配器满足我们所需要的操作即可
	template<class T, class Container = deque<T>>//适配器
	class stack
	{
	private:
		Container _con;
	};

STL中对stack和queue默认选择deque作为其底层容器,主要是因为:

  1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
  2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。
  3. 当然了这里你也可以显示调用你想用的容器适配器例如vector和list也都是可以的。

常见函数的模拟实现

入栈 - push(const T& x)

代码思路: 这里我们知道栈的基本结构就是先入栈的会后出,后进栈的先出,我们只需要在容器的尾部进行尾插,即可完成入栈,但是我们需要注意的是我们是尾插,所以再出栈的时候就直接出容器尾部的元素即可。

void push(const T& x)//入栈
{
	_con.push_back(x);//调用适配器的push_back即可
}

出栈- pop()

代码思路:刚刚我们说过栈先进后出,并且我们是通过尾插来模仿入栈的操作,所以我们的最后一个元素就是最后尾插进来的元素,要想模拟出栈的操作就是对其进行尾删即可。

void pop()//出栈
{
	_con.pop_back();//删除容器尾部的元素
}

获取栈顶元素 - const T& top()

代码思路: 我们是通过尾插来表示入栈,栈顶的元素就是最后一个入栈的元素,因此我们直接返回容器尾部的元素就可以模拟出获取栈顶元素的操作

const T& top()//获取栈顶元素
{
	return _con.back();//调用适配器返回尾部的元素
}

栈中的元素个数 - size_t size()

代码思路: 这个就比较简单了,我们通过适配器返回当前元素个数即可

size_t size()//栈中的元素个数
{
	return _con.size();
}

判断栈是否为空

代码思路: 同理直接调用适配器的函数即可

bool empty()//判断栈是否为空
{
	return _con.empty();
}

整体代码:

namespace bit 
{
	//template<class T> //传统的写法
	//class stack
	//{
	//	private:
	//	T* _a;
	//	int _top;
	//	int _capacity;
	//};
	template<class T, class Container = deque<T>>//适配器
	class stack
	{
	public:
		void push(const T& x)//入栈
		{
			_con.push_back(x);
		}

		void pop()//出栈
		{
			_con.pop_back();//删除容器尾部的元素就是出栈
		}

		size_t size()//栈中的元素个数
		{
			return _con.size();
		}

		const T& top()//获取栈顶元素
		{
			return _con.back();//返回队尾的元素
		}
		bool empty()//判断栈是否为空
		{
			return _con.empty();
		}

	private:
		Container _con;
	};
}



Queue的模拟实现

Queue的基本结构

代码思路:同理我们这里依然可以使用适配器帮助我们来模拟实现queue的基本结构,但是一定记住适配器里面的操作必须满足你所需要的操作

namespace bit
{
	template <class T, class Container = deque<T>>//调用适配器
	class queue
	{
	private:
		Container _con;
	};

}

常见函数的模拟实现

入队列- push(const T& x)

代码思路: 这里我们依然提一下,队列是先进先出,后进的后出和栈是完全相反的,所以我们在入队列的时候尾插的时候要记住,出队列的时候就是该容器的第一个元素先出,最后一个元素就是最后进去的元素就是最后出

void push(const T& x)//入队列
{
	_con.push_back(x);//队列先进去的先出去,入队列就直接尾插
}

出队列- pop()

代码思路:刚刚我们提到了因为我们是尾插来模拟的入队列,所以出队列的时候就要通过删除第一个元素来模拟出队列,但是这里需要注意的是Vector中是没有pop_front()这个函数的,所以我们的适配器只能是List和deque

void pop()//出队列
{
	_con.pop_front();//出队列就依次头出即可,这里就不能用vector了,vector没有pop_front
}

获取队头元素- const T& front()

代码思路: 刚刚提到了容器的第一个元素就是队头元素,因此我们只需要获取第一个元素即可。

const T& front()//获取队头元素
{
	return _con.front();//通过适配器获取队头元素
}

获取队尾元素- const T& back()

代码思路:因为我们是尾插,所以队尾元素就是最后一个进去的元素,所以通过适配器获得队尾元素即可。

const T& back()//获取队尾元素
{
	return _con.back();//调用适配器获取队尾元素
}

获取队列元素个数 - size_t size()

代码思路:这个和前面的栈同理就不过多的讲解了

size_t size()
{
	return _con.size();
}

判断队列是否为空 - bool empty()

代码思路: 这个也是一样的直接调用适配器里面的函数即可

bool empty()
{
	return _con.empty();//同理调用适配器判断是否为空
}

整体代码

namespace bit
{
	template <class T, class Container = deque<T>>
	class queue
	{
	public:
		void push(const T& x)//入队列
		{
			_con.push_back(x);//队列先进去的先出去,入队列就直接尾插
		}

		void pop()//出队列
		{
			_con.pop_front();//出队列就依次头出即可,这里就不能用vector了,vector没有pop_front
		}

		size_t size()
		{
			return _con.size();
		}

		bool empty()
		{
			return _con.empty();
		}

		const T& front()//获取队头元素
		{
			return _con.front();
		}

		const T& back()//获取队尾元素
		{
			return _con.back();
		}

	private:
		Container _con;
	};
}

好啦,今天的内容就到这里啦,下期内容预告STL中的优先级队列的使用与模拟实现.


结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。


🌏🗺️ 这里祝各位接下来的每一天好运连连 💞💞

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

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

相关文章

Apache Doris 基础 -- 部分数据类型及操作

您还可以使用SHOW DATA TYPES;查看Doris支持的所有数据类型。 部分类型如下&#xff1a; Type nameNumber of bytesDescriptionSTRING/可变长度字符串&#xff0c;默认支持1048576字节(1Mb)&#xff0c;最大精度限制为2147483643字节(2gb)。大小可以通过BE配置string_type_le…

2. Revit API UI 之 IExternalCommand 和 IExternalApplication

2. Revit API UI 之 IExternalCommand 和 IExternalApplication 上一篇我们大致看了下 RevitAPI 的一级命名空间划分&#xff0c;再简单讲了一下Attributes命名空间下的3个类&#xff0c;并从一个代码样例&#xff0c;提到了Attributes和IExternalCommand &#xff0c;前者是指…

Cisco Packet Tracer实验(二)

二、用交换机构建 LAN 构建物件如下&#xff1a; 四个PC 两个交换机 一个Multi Switch多功能拓展控制器 连线必须是这个直线&#xff01;&#xff01;&#xff01;不是虚线 最后实现效果如下&#xff1a; 全部的线是绿的&#xff0c;就表示是通的。 尝试一下&#xff0c;看PC…

JVM性能优化案例:减少对象频繁创建

JVM性能优化案例&#xff1a;减少对象频繁创建 案例背景 某金融应用系统在处理大量并发交易时&#xff0c;响应时间过长&#xff0c;并且有时出现内存溢出&#xff08;OutOfMemoryError&#xff09;的问题。经过分析&#xff0c;发现问题主要出在频繁的对象创建和较差的内存管…

热门开源项目OpenHarmony

目录 1.概述 1.1.开源项目的意义 1.2.开源项目对软件行业的促进作用 1.3.小结 2.OpenHarmony 2.1.技术架构 2.2.分布式软总线 2.2.1.架构 2.2.2.代码介绍 2.2.2.1.代码目录 2.2.2.2.说明 2.2.2.3.发现组网和传输 2.2.2.3.1.发现 2.2.2.3.2.组网 2.2.2.3.3.传输…

力扣148. 排序链表

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示例 3&…

数据分析常用6种分析思路(下)

作为一名数据分析师&#xff0c;你又没有发现&#xff0c;自己经常碰到一些棘手的问题就没有思路&#xff0c;甚至怀疑自己究竟有没有好好学过分析&#xff1f; 在上篇文章里&#xff0c;我们讲到了数据分析中的流程、分类、对比三大块&#xff0c;今天&#xff0c;我们继续讲…

PHP地方门户分类信息网站源码讯客分类信息系统源码(含手机版)

源码介绍 1.上传程序到网站根目录,访问http://域名/install/index.php 进行安装,不要直接打开网址&#xff0c;先直接安装; 2.安装完成后 后台恢复数据即可 默认帐号密码都是admin http://域名/admin/ 3.不要删除任何文件&#xff0c;因为删除文件或者修改代码可能造成错误 运…

vuejs3 pinia持久化存储

插件地址&#xff1a; 快速开始 | pinia-plugin-persistedstate 安装插件&#xff1a; 安装pinia后&#xff0c;再安装这个插件 npm i pinia-plugin-persistedstate 引入插件&#xff1a; 在main.ts或者main.js里 //main.ts或者main.js里import { createPinia } from pi…

C++ | Leetcode C++题解之第149题直线上最多的点数

题目&#xff1a; 题解&#xff1a; class Solution { public:int gcd(int a, int b) {return b ? gcd(b, a % b) : a;}int maxPoints(vector<vector<int>>& points) {int n points.size();if (n < 2) {return n;}int ret 0;for (int i 0; i < n; i…

94. 二叉树的中序遍历(Swift实现, 迭代)

题目描述 使用迭代方法解题 class TreeNode {var val: Intvar left: TreeNode?var right: TreeNode?init(_ val: Int) {self.val valself.left nilself.right nil} }func inorderTraversal(_ root: TreeNode?) -> [Int] {var result [Int]() // 用于存储中序遍历…

11.第十一章 字典

11. 字典 本章介绍另一种内置类型: 字典. 字典是Python最好的语言特性之一, 它是很多高效而优雅的算法的基本构建块.11.1 字典是一个映射 字典类似于列表, 但更加通用. 在列表中, 下标必须是整数. 而字典的下标(几乎)可以是任意类型. 字典包含下标(称为键)集合和值集合. 每个…

人工智能的前沿技术 博客 期刊 论文 推荐

在学习和关注人工智能的前沿技术时&#xff0c;有几个权威期刊和会议是非常重要的资源。以下是一些推荐的期刊和会议&#xff0c;涵盖了机器学习、深度学习、自然语言处理和生成式AI等领域的最新研究和进展&#xff1a; 博客 Andrej Karpathy’s blog - 深度学习领域知名专家…

在AI云原生时代应该如何应对复杂的算力环境

引言 随着在2019年ChatGPT4的爆火,AI这个之前常常被人觉得非常高深的技术渐渐的被越来越多的人们所了解,越来越多的公司、组织和开发者开始投入AI的使用和开发中来.随着AI和LLM的火热,算力资源也变的越来越紧缺,所以如何高效的管理和使用算力资源也变成了必须要面对的问题。 …

13. 第十三章 案例研究-选择数据结构

13. 案例研究-选择数据结构 到这里尼应该已经学会了Python的核心数据结构, 也见过了一些使用它们的算法. 如果你想要更多地了解算个发可以阅读第21章. 本章配合联系介绍一个案例分析, 帮你思考如何选择数据结构并如何使用它们.13.1 单词频率分析 1. 练习1 编写一个程序, 读入…

【C语言函数实现节选1】

前言&#xff1a; 通过前面的博客&#xff0c;C语言基本知识基本上我已给大家分享完成&#xff01;接下来我会通过两篇博客结 合前面的知识实现一下常见的函数。实现方式不唯一&#xff0c;大家只要大体思路符合都是可以的&#xff0c;在学习 的过程中尽量自己先实现&#xf…

安装VM虚拟机并创建一个Linux CentOS 7无桌面系统

一、安装vm虚拟机软件 1 下载vm压缩包 百度网盘链接 链接&#xff1a;https://pan.baidu.com/s/1ipiWatBr0wHKMt5c5nQirw?pwdwoy2 提取码&#xff1a;woy2 2.下载完毕后&#xff0c;先将杀毒软件关闭 全部关闭 3. 解压后按照步骤安装即可 按照按照步骤&#xff0c;观看…

C++240613

自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面 要求&#xff1a;每行代码都有注释 #include "my_widget.h"My_Widget::My_Widget(QWidget *parent): QWidget(parent) {//设置窗口的标题this->setWindowTitle("真爱生命&#xff0c;远离赌博&…

Vue31-生命周期的简介

一、需求&#xff1a;文字的透明度递减 示例&#xff1a; 对象的简写形式 new vue({ key:value, key:value, 。。。。。。 }) 二、代码的实现 注意&#xff1a;JS不擅长小数的计算&#xff01;&#xff01;&#xff01; 此写法不好&#xff01;&#xff01;&#xff01;追求…

借力AI,助力网络钓鱼(邮件)检测

引言 互联网时代&#xff0c;邮件系统依然是人们工作、生活中的很重要的一部分&#xff0c;与此同时&#xff0c;邮件系统的发展带来的钓鱼邮件问题也成为网络中的最大的安全隐患之一。本文将为大家解开网络钓鱼&#xff08;邮件&#xff09;的神秘面纱&#xff0c;一探究竟&a…