stack与queue的简单封装

news2024/9/28 9:28:28

    前言: stack与queue即栈和队列,先进后出/先进先出的特性我们早已了然于心,  在学习数据结构时,我们利用c语言实现栈与队列,从结构体写起,利用数组或指针表示他们的数据成员,之后再一个个实现他们的函数接口,简单来说我们是直接手撕栈和队列的。

但对于c++来说,c++提供了模板,提供了标准模板库,利用这些们只需要实现它的特性,然后再封装它即可。

在实现之前,我们再来了解一下何为适配器?

适配器

本质上是一种设计模式-适配器模式:

Adapter(适配器模式)属于结构型模式,结构性模式关注的是如何组合类与对象,以获得更大的结构,我们平常工作大部分时间都在与这种设计模式打交道。

意图:将一个类的接口转换成客户希望的另一个接口。Adapter 模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。
对于统一多个类的接口适配器模式就比较适用。

适配器, 在STL中扮演着转换器的角色,用于将一种接口转换成另一种接口,从而是原本不兼容的接口能够很好地一起运作。

容器、迭代器、和函数都有适配器,  适配器不提供迭代器。

栈的简单封装

一般对于我们自己来说实现一个栈,利用c++提供的STL我们可以直接封装,比如我们直接利用vector表示整个栈,出栈即尾删,入栈即尾插,获取栈顶元素即返回数组末尾元素,其他接口我们也不难实现:

template <class T>class stack      
{
public:
	//栈的重要接口
	//入栈
	viod push(cosnt T& x)
	{
		_container.push_back(x);//直接调用尾插
	}
	//出栈
	void pop()
	{
		_container.pop_back(x);//直接调用尾删
	}
	//获取栈顶元素
	const T& top()
	{
		return _container.back();//返回尾元素
	}
	//大小
	size_t size()
	{
		return _container.size();
	}
	//判空
	bool empty()
	{
		return _container.empty();
	}

private:
	//直接利用容器
     vector<T>> _container;

};

 添加容器模板参数(适配器)

    对于栈我们知道本质是数组,那么直接调用数组模板即可,但对于栈的实现我们发现不仅仅直接利用数组,利用链表也是可以实现栈的,其次由于在设计标准模板库时根据泛型编程的思维,这使得接口其功能都是一样的()。

那么在实现栈的时候,不仅仅利用一种模板,而是多模板,这使得我们在设计实现栈时,可以提供一个容器模板(根据不同的容器也能实现栈),因此我们还添加了Container(容器模板),达到实现不同容器,统一接口的实现。

template <class T,class Container>class stack      
{
public:
	//栈的重要接口
	//入栈
	void push(const T& x)
	{
		_container.push_back(x);//直接调用尾插
	}
	//出栈
	void pop()
	{
		_container.pop_back();//直接调用尾删
	}
	//获取栈顶元素
	const T& top()
	{
		return _container.back();//返回尾元素
	}
	//大小
	size_t size()
	{
		return _container.size();
	}
	//判空
	bool empty()
	{
		return _container.empty();
	}
	const T& front()
	{
		return _container.front();
	}
	const T& back()
	{
		return _container.back();
	}
private:
	//直接利用容器
	Container _container;

};

  对于这里的容器模板,其实就是适配器,通过参数控制不同容器适配出同样效果的数据结构(感觉这也是泛型编程的特点,不追求底层,只看当前的功能)。

队列的简单封装

通过对栈的是实现,我们也可以利用适配器这种方式来实现队列,不过需要注意的是:

我们在选用容器的时候还是要应当注意容器是否满足我们在实现某个功能时,提供所需要的接口,对于队列,这里使用vector就不行了,并不能一股脑认为是个容器都可以。

template<class T, class Container = deque<T>>class queue
{
public:
	//入队
	void push(const T& x)
	{
		_con.push_back(x);
	}
	//出队
	void pop()
	{
		_con.pop_front();
	}

	void top()
	{
		return _con.front();
	}
	size_t size()
	{
		return _con.size();
	}
	const T& front()
	{
		return _con.front();
	}
	const T& back()
	{
		return _con.back();
	}
	bool empty()
	{
		return _con.empty();
	}
private:
	Container _con;

};

库中的实现


  利用适配器我们可以将能实现的容器集合在一起,控制参数来控制容器,那么既然是参数,我们想这里也应该可以设置缺省参数的,那么缺省参数如何设置呢?我们可以看看库中的实现:

初识双端队列

库中这里设置的缺省参数是双端队列,我们可以看看双端队列:

 首先对于双端队列,我们不要认为他是一个队列,其次我们在观察它的接口:

双端队列,本质上是一个顺序表,可以看到它的接口与vector和list非常相似,从功能上来说,他是将vector与list的功能集合到一起,同时具有两种结构的接口(包括尾插,尾删,头插,头删,正反向迭代器,[ ]访问元素,插入,删除等接口),可以看到非常之牛,它好像同时满足了vector和list的所有优点:

1.vector的连续地址,支持快速访问。

2.list的高效率随机位置插入。

犹如六边形战士,那么真实情况果真如此吗?事实并非如此。

我们可以了解一下他的结构,因为能支持数组随机访问,且能随机插入,那么其空间应该是连续的,但不完全连续:

即利用指针,将各个数组连接起来,指针被存放在叫中控数组的地方,存放数据的叫做buffer数组。

迭代器设计:

 可以看到迭代器是由四个数据封装起来的,其中第一个位置的cur指向的是当前数组的第一个位置,第二个位置的first指向的是数组第一个位置,第三个last指向的是数组最后位置,二级指针node指向的是中控数组里的某个指针。

以这样的方式封装了begin与end这两个表示开头语结尾的迭代器。

        对于双端队列,它的数据插入是从中间开始的,如若头或尾某个地方的数据已经满了,那么他会新开一个buffer数组,将数组存放起来(头部插入,放数组后面,尾部插入放数组前面),再连接起来,当然如果数据够多使得中控数组都已经插入满了,那么需要扩容中控数组,不过代价会比较低,但是对于中间插入数据,如若中间的某个位置的buffer数组已经满了,那么有两种选择方案:

扩容或者挪动数据,如何选择看你的取舍:

若果是扩容的话,因为我们[ ]访问数据对于同样大的数组访问速度会比较快,我们可以很好的计算出它的位置从而访问它(比如我们对数组的大小取余或取整,就可以知道是某个数组的第几个),若扩容,则该位置访问是比较困难的。

如果是挪动数据的话,整体后挪数据,数据量太大,那么代价就非常大了,效率会特别低。

这样一看其实是对于双端队列,我们头插尾插数据时效率是比较高的,但对于中间插入数据实在是不太行啊,这也是为什么叫双端队列,目的也是让我们去操作它的两端数据,不去中间搞事。

那么回过头来看选用双端队列用作我们的栈和队列的适配器,其实是比较不错的,只操作两端的数据,效率还是比较高的。

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

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

相关文章

Linux 故障定位手段之保存某个时间段内的top结果

在Linux中对故障原因进行定位时&#xff0c;除了查看对应的软体运行日志、OS运行日之外&#xff0c;还可以查看 top 的资源消耗结果。 参考语句&#xff1a; 以CPU为基准列进行排序记录TOP结果 nohup top -d 1 -b -o %CPU | tee -a /tmp/cpu.txt & 语句含义&#xff1a;每…

etc目录下的profile.d文件目录设置环境变量和全局脚本

一、设置环境变量 etc目录下的profile.d文件目录 /etc/profile.d 1、编写 vi test.sh文件内容 # jdk变量 export ZHK_HOME/root export PATH$PATH:$ZHK_HOME/test # 可以取出来ZHK_HOME变量给ZZZ_HOME赋值 export ZZZ_HOME${ZHK_HOME}/test2、刷新 执行source /etc/profile …

34.CSS魔线图标的悬停效果

效果 源码 index.html <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Icon Fill Hover Effects</title> <link rel="stylesheet" h…

【深度学习实验】前馈神经网络(final):final

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 构建数据集&#xff08;IrisDataset&#xff09; 2. 构建模型&#xff08;FeedForward&#xff09; a. __init__(初始化) b. forward(前向传播) 3.整合训练、评估…

Mojo:新型AI语言中的7个令人惊叹的Python升级,用简单的英语解释人工智能

Mojo&#xff1a;新型AI语言中的7个令人惊叹的Python升级 编程之美 用简单的英语解释人工智能 编程之美 由Coding Beauty设计的图像&#xff0c;使用Mojo标志和Python标志。 它比C更快&#xff0c;与Python一样简单&#xff0c;但速度提高了35000倍。 进入Mojo&#xff1a;一种…

冒泡排序与选择排序(最low的两兄弟)

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 前言&#xff1a; 在我们的生活中&#xff0c;无处不在用到排序&#xff0c;比如说成绩的排名&#xff0c;淘宝&#xff0c;京东等等商品在各个方面的排序&#xff0c;这样看来一个好的算 法很重要&#xff0c;接下来我们要先…

深度学习自学笔记四:浅层神经网络(一)

一、神经网络概述 神经网络是一种模仿人脑神经系统结构和功能的计算模型。它由大量相互连接的人工神经元组成&#xff0c;并通过这些神经元之间的信息传递来进行计算和学习。 神经网络的基本组成单元是神经元&#xff0c;也称为节点或单元。每个神经元接收来自其他神经元的输…

第一百五十二回 自定义组件综合实例:游戏摇杆三

文章目录 内容回顾优化性能示例代码我们在上一章回中介绍了 如何实现游戏摇杆相关的内容,本章回中将继续介绍这方面的知识.闲话休提,让我们一起Talk Flutter吧。 内容回顾 我们在前面章回中介绍了游戏摇杆的概念以及实现方法,并且通过示例代码演示了实现游戏摇杆的整个过程…

取消github向邮箱推送邮件及修改密码

取消或者说禁止github向邮箱推送邮件&#xff0c;因为量太大了&#xff0c;没多久就上万封邮件&#xff0c;于是取消订阅或者推送。 1、登录github 2、点击右上角头像&#xff0c;然后点击Settings 3、点击Notifications&#xff08;通知&#xff09; 4、取消各种推送&#x…

SpringBoot开发实战(微课视频版)

ISBN: 978-7-302-52819-7 编著&#xff1a;吴胜 页数&#xff1a;311页 阅读时间&#xff1a;2023-06-24 推荐指数&#xff1a;★★★★☆ 本文介绍SpringBoot 2.0.5 、JDK 1.8&#xff0c;虽然现在已经不维护了&#xff0c;但是大体的流程还是对口的&#xff0c; 而且书里面讲…

新手学习:ArcGIS对shp文件裁剪

新手学习&#xff1a;ArcGIS对SHP文件裁剪 新手学习 记录每个步骤&#xff0c;因为有很多控件可能刚开始还不熟悉&#xff0c;根本不知道在哪里&#xff0c;所以写的比较详细。 1.添加要裁剪的shp文件 2.查看shp文件的地理坐标系 双击shp文件&#xff0c;就可以查看shp文件的…

LeetCode【174. 地下城游戏】

一片丹心图报国&#xff0c;两行清泪为忠家。——于谦 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里&#xff0c;他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康…

【Linux】系统编程基于环形队列生产者消费者模型(C++)

目录 【1】引入POSIX信号量 【1.1】初始化信号量 【1.2】销毁信号量 【1.3】等待信号量 【1.4】发布信号量 【2】基于环形队列的生产消费模型 【2.1】生产消费模型打印数字模型 【2.2】生产消费模型计算公式模型 【2.3】生产消费模型计算公式加保存任务模型 【1】引入…

###Data Structure###考研重点

顺序表 顺序表 &#xff08;此代码i是序号而非角标&#xff09; 结构体&#xff1a; 插入&#xff1a;从最后一个元素逐个往后移一位 删除&#xff1a;从删除位置的下一个把每个提前一位 顺序&#xff08;循环&#xff09;队列 结构体 判断队满 &#xff08;总结&#xff…

Dependency ‘org.redisson:redisson:‘ not found解决方法 三种刷新Maven项目的方法

报错情况 在pom中导入redisson包 <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId> </dependency> 爆红&#xff0c;还显示Dependency org.redisson:redisson: not found。 由于报错已经解决&#xff0c;…

postgresql-触发器

postgresql-触发器 触发器概述创建触发器管理触发器删除触发器事件触发器创建事件触发器修改触发器删除事件触发器 触发器概述 PostgreSQL 触发器&#xff08;trigger&#xff09;是一种特殊的函数&#xff0c;当某个数据变更事件&#xff08;INSERT、UPDATE、 DELETE 或者 TR…

6 年大厂程序员跟你聊聊,算法其实没那么难,要怎么准备比较好

说起算法&#xff0c;许多程序员都会一顿哀嚎&#xff0c;为啥面试要靠算法这个东西。不过这个不是咱们讨论的重点。&#xff08;我们无法改变这种现状&#xff0c;那就改变自己&#xff09; 今天&#xff0c;我们一起来聊一下&#xff0c;程序员面试的时候该如何准备算法。 …

数字图像基础,数字图像处理中的基础内容(数字图像处理概念 P2)

文章目录 人类视觉系统构造数字图像生成采样和量化像素之间的基本关系 人类视觉系统构造 锥状体&#xff1a;明亮的视野杆状体&#xff1a;微光或暗视野图像成像原理&#xff1a;类似照相机亮度适应现象&#xff1a;人的视觉不能同时在一个范围内工作同时对比现象&#xff1a;…

怒刷LeetCode的第14天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;动态规划 方法二&#xff1a;栈 方法三&#xff1a;双指针 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;二分查找 方法二&#xff1a;线性扫描 方法三&#xff1a;递归 第三题 题目来源 …

【WSL】仅适用于装C盘情况-用WSL在win10安装LInux

研究了一点点伪分布式的内容。决定搞一个Linux系统玩一下 参考来自微软官方安装步骤&#xff1a; 旧版 WSL 的手动安装步骤 https://learn.microsoft.com/zh-cn/windows/wsl/install-manual WSL全称为&#xff0c;Windows Subsystem for Linux 法一&#xff1a;应用商店装 查…