stack和queue模拟实现

news2024/10/7 8:21:57

前言

上一期我们介绍了stack和queue的使用,本期我们来模拟实现一下他们!

本期内容介绍

容器适配器 

deque介绍

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

stack 模拟现实

queue 模拟实现

什么是容器适配器?

适配器是一种设计模式,该种模式是将一个类的接口转换为用户希望的另一个接口!

什么是设计模式?

设计模式是一套被反复使用的,多数人知晓的,经过分类编目的,代码设计经验的总结。

总结:设计模式就是一种常用的编程套路,该套路被很多人知晓和使用,具有可靠性!

常见的设计模式有:单例设计模式、工厂设计模式等。

举个例子:

你平时手机没电了,你是拿充电器先到插板上去充,而不是直接去拿电线充。因为电线直接充是不符合我们的需求的(一下子弄不好你就被干没了)!我们要用插板提供的接口插充电器才可以充!其实本质你手机充的还是电线里面的电。只是把他转换了一下!充电器就像是一个适配器,将电源的接口转换成手机充电口的接口,使得手机可以与电源连接起来充电。同样地,容器适配器也起到了类似的作用,它将一个容器的接口转换成另一个容器的接口,使得原本不兼容的容器能够协同工作。

deque介绍

stack和queue中虽然也可以存放元素,但是STL并没有将他们划分到容器的行列里面!而是将其称为:容器适配器,这里是因为stack和queue只是对其他的容器进行了包装,STL中stack和queue底层默认deque, deque就是我们在上一期介绍stack和queue的时候,看到了他们的模板参数多了一个的那个容器类型的默认容器!

什么是deque?

deque到底是什么呢?上一期专门没有介绍,就等到这一期来介绍!

deque叫双端队列!是一种双开口的"连续"空间的数据结构。双开口的含义是:可以在头和尾两端进行插入和删除操作!而且时间复杂度为O(1),与vector相比头插效率高,不需要在头删时挪动大量的数据了,与list相比,空间利用率比较高!所以我们可以认为他是list和vector的结合版!可以支持元素的随机访问。支持头尾的插入删除,而且效率很高!

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

这个中控数组实际上一个数组指针!里面存的就是每个小段的数组的地址!这个中控数组是可以扩容的!!

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

deque的迭代器也很复杂:

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

它的底层搞了两个迭代器start和finish一个指向第一个buffer小段数组,另一个指向最后一个buffer小数组,遍历时,从第一个buffer开始,如果不到最后一个buffer的最后一个位置即finish的最后一个end就到下一个buffer继续遍历!直到遍历完!

deque是如何用下标+[]来访问的?

因为中控数组中的每个小buffer数组的长度都是一样大的!所以我们在访问第i个位置时,通过 i / N 获取他是在那个buff数组,再根据 i % N来确定他是在第几个!从而实现了下标遍历~!

deque的缺陷

与vector相比,deque的优势是:在头部插入和删除的时候,不需要移动元素,效率特别高,而在扩容时也不需要移动大量的元素,因此这里是效率比vector高的!

与list相比,它的底层的空间是连续的,空间利用率高,不需要额外的存储字段!

但是,deque也有很致命的缺陷:

不适合遍历,一位在遍历时,deque的迭代器要频繁的去检测其是否移动到了都一小段的边界,导致效率下降!所以在实际中,需要线性结构中一般优选的是vector和list!

不适合在中间插入删除、因为你在某个中间的buffer插入时,如果满了得扩容,删除时怎么删??你不可能说--size吧,人家下标可不管这些,解决的办法就是删除时缩容,但是缩容后就有新问题,如何知道第i个位置的元素?导致效率降低!

以及它的[]的效率很一般!下面有代码验证:

void test_op1()
{
	srand(time(0));
	const int N = 1000000;

	deque<int> dq;
	vector<int> v;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand() + i;
		v.push_back(e);
		dq.push_back(e);
	}

	int begin1 = clock();
	sort(v.begin(), v.end());
	int end1 = clock();

	int begin2 = clock();
	sort(dq.begin(), dq.end());
	int end2 = clock();

	printf("vector:%d\n", end1 - begin1);
	printf("deque:%d\n", end2 - begin2);
}

我们知道sort的底层会大量的用到[],结果差了三倍多!!!

第二个:

void test_op2()
{
	srand(time(0));
	const int N = 1000000;

	deque<int> dq1;
	deque<int> dq2;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand() + i;
		dq1.push_back(e);
		dq2.push_back(e);
	}

	int begin1 = clock();
	sort(dq1.begin(), dq1.end());
	int end1 = clock();

	int begin2 = clock();
	// vector
	vector<int> v(dq2.begin(), dq2.end());
	sort(v.begin(), v.end());
	dq2.assign(v.begin(), v.end());
	int end2 = clock();

	printf("deque sort:%d\n", end1 - begin1);
	printf("deque copy vector sort, copy back deque:%d\n", end2 - begin2);
}

这个是把一个deque的数据拷贝到vector排完了再拷回来,都比deque快:

所以ton过这两个栗子足以证明deque的[]效率可见一般了~!

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

STL选择让他默认为栈和队列的原因有两个:

1、stack和queue不需要遍历,他们根本没有迭代器。只是需要在固定的一端或两端进行插入和删除操作!

2、在stack中元素增加时,与vector相比deque的扩容效率更高(deque扩容不需要移动大量的数据)。

综上两点,deque完美的解决stack和queue的问题,而且正好弥补了用vector和list的缺陷!所以STL就选择了他作为默认的容器!

OK,我们来看看它的接口:

直接包含了vector和list所有的好用接口!!!

stack的模拟实现

我们以前在数据结构的时候,实现栈使用的是单链表或顺序表!这里你也可以接着这样玩,直接用vector和list。但是我这里就不这样玩了,我直接来使用deque!

    template<class T, class Container = deque<T>>
	class stack
	{
	public:
		stack()
		{}

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

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

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

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

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

		void pop()
		{
			assert(!empty());
			_con.pop_back();
		}

	private:
		Container _con;
	};

这里都很简单不在逐一解释!

需要注意的是:你可以不用写这个stack的默认构造!因为stack这个类里面只有一个自定义类型的变量!所以你不写编译器默认生成的那个就自己去调用调他自己成员的默认构造了!

另外,这里选择的是尾部实现的,你也可以选择头部实现!

queue模拟实现

同样的队列这里你也可以和数据结构那样搞个链表玩!介绍了deque那必然用它~!

    template<class T, class Container = deque<T>>
	class queue
	{
	public:
		queue() 
		{}

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

		size_t size() const
		{
			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();
		}

	private:
		Container _con;
	};

和上面同样你也可以不写默认构造!另外注意的是:插入是尾插,删除是头删

OK,我测试一下:

没有问题~!OK,本期分享就到这里!好兄弟,我们下期再见~!

结束语:心怀理想,勇往直前!

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

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

相关文章

《QT实用小工具·二十三》 Ntp校时类

1、概述 源码放在文章末尾 该项目实现了 Ntp校时类 &#xff0c;包含如下功能&#xff1a; 可设置Ntp服务器IP地址。 推荐用默认的阿里云时间服务器 ntp1.aliyun.com 收到时间信号发出。 时间精确到秒。 下面是demo演示&#xff1a; 项目部分代码如下&#xff1a; #if…

【Axure高保真原型】马赛克效果

今天和大家分享动态画出马赛克效果的原型模板&#xff0c;鼠标按着左键拖动&#xff0c;可以在对应位置拖出马赛克&#xff0c;具体效果可以观看下方视频或者打开预览地址体验。 【原型效果】 【Axure高保真原型】马赛克效果 【原型预览含下载地址】 https://cspfgk.axshare.…

Redis中的集群(四)

集群 槽指派 CLUSTER ADDSLOTS命令的实现 CLUSTER ADDSLOTS命令接受一个或多个槽作为参数&#xff0c;并将所有输入的槽指派给接收该命令的节点负责: CLUSTER ADDSLOTS <slot> [slot ...]CLUSTER ADDSLOTS命令的实现可以用以下伪代码来表示: def CLUSTER_ADDSLOTS(*…

网工内推 | 安全运维、服务工程师,软考中级、CISP优先,六险一金

01 华成峰科技 招聘岗位&#xff1a;安全运维工程师 职责描述&#xff1a; 1、负责安全产品的运维管理&#xff0c;包括设备升级变更、策略配置优化、设备巡检等&#xff1b; 2、负责7*24小时安全监控与应急响应&#xff0c;包括态势感知日志监测、安全事件分析及处置等&#…

应急响应-挖矿脚本检测指南威胁情报样本定性文件清除入口修复

一、演示案例-挖矿样本-Win&Linux-危害&定性 危害&#xff1a;CPU拉满&#xff0c;网络阻塞&#xff0c;服务器卡顿等 定性&#xff1a;威胁情报平台上传解析分析&#xff0c;文件配置查看等windows样本 linux样本 二、演示案例-Linux-Web安全漏洞导致挖矿事件 某公司…

真·人工智障!“弱智贴吧”竟被用来训练大模型

离了个大谱&#xff0c;弱智吧登上正经AI论文&#xff0c;还成了最好的中文训练数据&#xff1f;中国科学院、北京大学、中国科学技术大学、滑铁卢大学以及01.ai等十家知名机构联合推出了一款专注于中文的高质量指令调优数据集——COIG-CQIA。 在大型语言模型的研究领域&#x…

力矩,转矩,扭矩的理解——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 力矩、转矩和扭矩是力学中常用的概念&#xff0c;它们描述了力的转动效果。虽然这三个词经常被互换使用&#xff0c;但它们之间实际上存在细微的差别。本文将从力学的基本原理出发&#xff0c;深入剖析这三个概念的含义…

Linux(centos7)部署spark

Spark部署模式主要有4种&#xff1a;Local模式&#xff08;单机模式&#xff09;、Standalone模式&#xff08;使用Spark自带的简单集群管理器&#xff09;、Spark On Yarn模式&#xff08;使用YARN作为集群管理器&#xff09;和Spark On Mesos模式&#xff08;使用Mesos作为集…

生鲜蔬果配送小程序开发攻略

随着互联网的快速发展&#xff0c;电商行业也在不断壮大。生鲜蔬果作为日常生活必需品&#xff0c;在线销售的需求也在不断增加。为了满足这一需求&#xff0c;开发一款生鲜蔬果配送小程序成为了必要的事情。下面就给大家介绍开发这款小程序的攻略。 1. 确定开发需求 首先&…

计算机组成结构—外部存储器

目录 一、磁盘存储器 1. 磁表面存储器和磁记录原理 2. 硬磁盘的分类和基本结构 &#xff08;1&#xff09;硬磁盘存储器的分类 &#xff08;2&#xff09;硬磁盘存储器的组成 3. 磁盘的工作原理 &#xff08;1&#xff09;磁盘存储区域 &#xff08;2&#xff09;磁盘地…

Canal--->准备MySql主数据库---->安装canal

一、安装主数据库 1.在服务器新建文件夹 mysql/data&#xff0c;新建文件 mysql/conf.d/my.cnf 其中my.cnf 内容如下 [mysqld] log_timestampsSYSTEM default-time-zone8:00 server-id1 log-binmysql-bin binlog-do-db mall # 要监听的库 binlog_formatROW2.启动数据库 do…

xss.pwnfunction-Ugandan Knuckles

这个是把<>过滤掉了所以只能用js的事件 ?weya"onfocus"alert(1337)" autofocus"

什么是redis? 如何在SpringBoot中集成和操作redis?

喜欢就点击上方关注我们吧&#xff01; 本篇将带你快速了解什么是redis&#xff0c;以及学会如何在SpringBoot工程下集成和操作redis数据库。 一、概述 1、定义 Redis是一个基于内存的key-value 结构数据库。 1&#xff09;特点&#xff1a; 1、基于内存存储&#xff0c;读写性…

顺序表讲解

一.数据结构 在学习顺序表之前&#xff0c;我们先需要了解什么是数据结构。 1.什么是数据结构呢&#xff1f; 数据结构是由“数据”和结构两词组合而来。 什么是数据呢&#xff1f; 你的游戏账号&#xff0c;身份信息&#xff0c;网页里的信息&#xff08;文字&#xff0c…

体验Docker快速部署微信机器人

找到一个 Docker 部署微信机器人的镜像&#xff0c;简单测试一下。 1 使用 Docker 部署 1.1 拉取最新镜像 docker pull dannicool/docker-wechatbot-webhook1.2 Docker 部署 docker run -d --name wxBotWebhook -p 3001:3001 \ -v ~/wxBot_logs:/app/log \ dannicool/docker…

『VUE』11. 操作数组的方法(详细图文注释)

目录 vue中操作数组的方法会修改原数组的 会进行渲染更新不修改原数组的 不会进行渲染更新 push自动渲染concat 赋值渲染总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 vue中操作数组的方法 vue中数组数据呈现在网页,只检测…

【数据结构】-- 单链表 vs 双向链表

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…

珠海华发实业股份有限公司副总毛冰清莅临天府锋巢直播产业基地考察调研

3月19日&#xff0c;珠海华发实业股份有限公司副总毛冰清拜访天府锋巢直播产业基地&#xff08;以下简称天府锋巢&#xff09;&#xff0c;由产业招商总负责人姜国东进行接待。 基地建设情况 姜国东负责人介绍到&#xff0c;天府锋巢是由德商产投携手无锋科技于兴隆湖落地的成都…

从误差分解看Few-shot的核心问题

FSL训练过程一般都是最小化经验误差ERM。 同时&#xff0c;由于现实任务的实际数据分布 是未知的&#xff0c;因此无法找到一个最优的参数组合 &#xff0c;能最小化期望损失&#xff08;最小值多少也是未知的&#xff09;&#xff0c;我们能做的实际上是尽可能的去找一个参数…

基于SpringBoot + Vue实现的在线答疑系统设计与实现+毕业论文+答辩PPT

介绍 学生角色&#xff1a; 1.注册、登录功能&#xff1a;学生可以通过系统完成注册和登录操作&#xff0c;进入学生专属界面。 2.个人信息修改功能&#xff1a;学生可以查看和修改自己的个人信息&#xff0c;包括姓名、联系方式等。 3.问题发布功能&#xff1a;学生可以在线发…