C++:deque的概念以及stack和queue的模拟实现

2023-09-20 16:00:21

本篇主要总结的是stackqueue的模拟实现以及deque的原理

stack的模拟实现

和前面的模拟实现相同,首先要看官方实现的功能

在这里插入图片描述

在这里插入图片描述

这里引入了Container的概念,从字面意思来看,也就是说,在实例化模板的时候实际上是需要实例化两个参数的,一个是栈内元素的数据类型,一个是容器的类型,这里通过缺省参数给定了一个deque,因此平时使用的时候不需要实例化第二个参数,关于deque的概念后面再进行讲解

从中可以看出,stack的实现是以一个容器为模板,在这个模板的基础上引申出了栈的概念,因此在模拟实现的过程中相对容易一些

#include <iostream>
#include <vector>
#include <list>
#include <deque>

namespace mystack
{
	template <class T,class Container>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		bool empty()
		{
			return _con.empty();
		}
		int size()
		{
			return _con.size();
		}
		const T& top()
		{
			return _con.back();
		}
	private:
		Container _con;
	};
}

但是在实际的栈的实现中,是使用带有缺省参数的模板参数,在容器的实现中是使用的是deque,因此在使用STL中的模板实例化只需要实例化第一个参数即可,默认是使用的是deque,也可以实例化为vectorlist

#include "stack.h"
#include <stack>


// 采用vector来当容器生成栈
int main()
{
	std::stack<int, std::vector<int>> s;

	// 入栈
	s.push(1);
	s.push(2);
	s.push(3);
	s.push(4);

	// 出栈
	while (!s.empty())
	{
		std::cout << s.top() << " ";
		s.pop();
	}

	return 0;
}
#include "stack.h"
#include <stack>


// 采用list来当容器生成栈
int main()
{
	std::stack<int, std::list<int>> s;

	// 入栈
	s.push(1);
	s.push(2);
	s.push(3);
	s.push(4);

	// 出栈
	while (!s.empty())
	{
		std::cout << s.top() << " ";
		s.pop();
	}

	return 0;
}

deque

那么下面引入deque的概念,什么是deque,它的用法又是什么?

还是从cplusplus中查阅它的概念

deque的概念

deque也被叫做双端队列,从名字可以看出通俗来说它就是在两端都可以进出的队列,因此可以随意的头插头删尾插尾删

在这里插入图片描述

deque的底层实现方式

从上面的内容可以知道,deque可以实现在容器两端进行插入删除的操作,那其内部是如何进行工作的?

在这里插入图片描述
上面是两个容器的不同点,其实可以看出vector的优点其实就对应的是list的缺点,而list的优点就对应了vector的缺点,因此才需要根据不同的实验需求选择对应的容器来使用

deque的原理

在这里插入图片描述
deque的原理就是采用了一个中控数组用来管理每一个小数组,所以中控数组是一个指针数组,其中存储的是每一个小数组的指针,当需要插入元素的时候,就在这个中控数组的中间部分的指针指向的元素中进行插入,这样的模式就导致它具备了向前面插入数据,也具备了向后面插入数据的能力

向头部和尾部插入数据:

在这里插入图片描述


如果头部有数据继续头插,那么就会开辟额外的小数组用来存储

在这里插入图片描述
但是这样就产生了一个问题,如果中控数组控制的小数组已经排满了数据,但是我还要实施插入的操作应该如何实现?

  1. 可以整体挪动数据,把所有数组向后挪动一位
  2. 可以对单个小数组进行扩容,使得每一个小数组的长度不一样

这是两种扩容的思路,如果采用第一种思路,那么在挪动数据的时候效率会很低,但是优势是进行下标的随机访问的时候拥有更高效的功能
如果采用的是第二种思路,那么在插入数据的时候成本很低,但是在访问的时候就有较高的计算成本

因此两种扩容思路都有其好的一点和坏的一点,具体如何实施看对于容器的需求如何

在实际的使用场景中,对于deque其实是不常用的,因为它兼容了vectorlist的部分优势,但是在随机访问的情况下不如vector,在插入删除数据的方面不如list,只是出于一个较为兼容的容器,在实际开发中应用场景并不多

在这里插入图片描述

那为什么会选择deque作为底层容器的实现?

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()pop_back()操作的线性结构,都可以作为stack的底层容器,比如vectorlist都可以; queue是先进先出的特殊线性数据结构,只要具有push_back()pop_front()操作的线性结构,都可以作为queue的底层容器,比如list

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

  1. stackqueue不需要遍历(因此stackqueue没有迭代器),只需要在固定的一端或者两端进行操作
  2. stack中元素增长时,dequevector的效率高(扩容时不需要搬移大量数据); queue中的元素增长时,deque不仅效率高,而且内存使用率高,结合了deque的优点,而完美的避开了其缺陷

queue的模拟实现

#include <iostream>
#include <vector>
#include <list>
#include <deque>

namespace myqueue
{
	template <class T,class Container=std::deque<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();
		}
		bool empty()
		{
			return _con.empty();
		}
		int size()
		{
			return _con.size();
		}
		const T& front()
		{
			return _con.front();
		}
		const T& back()
		{
			return _con.back();
		}
	private:
		Container _con;
	};
}
#include "queue.h"

int main()
{
	myqueue::queue<int> q;

	// 插入数据
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);
	q.push(5);

	// 打印数据
	while (!q.empty())
	{
		std::cout << q.front() << " ";
		q.pop();
	}

	return 0;
}

这里直接使用了deque作为缺省参数,因此实例化只需要使用一个参数即可

更多推荐

MySQL如何进行增量备份与恢复?

目录一、MySQL介绍二、增量备份三、备份恢复一、MySQL介绍MySQL是一款开源的关系型数据库管理系统(RDBMS),它以其可靠性、灵活性和易于使用而备受赞誉。以下是关于MySQL数据库的介绍:MySQL是由瑞典公司MySQLAB开发,随后被SunMicrosystems收购,最终被甲骨文公司(OracleCorp

计算机竞赛 机器学习股票大数据量化分析与预测系统 - python 计算机竞赛

文章目录0前言1课题背景2实现效果UI界面设计web预测界面RSRS选股界面3软件架构4工具介绍Flask框架MySQL数据库LSTM5最后0前言🔥优质竞赛项目系列,今天要分享的是🚩机器学习股票大数据量化分析与预测系统该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!🥇学长这里给一个题目综合评分(每项满分5分)

【学习】一致性哈希与哈希环

一致性哈希一致性哈希(ConsistentHashing)是一种用于数据分布和负载均衡的算法,其核心思想是将数据和节点都映射到一个虚拟的哈希环上,并通过哈希值来确定数据应该分布到哪个节点上。以下是一致性哈希的基本实现步骤:1、确定哈希函数:首先,选择一个合适的哈希函数,它将数据映射到一个足够大的哈希空间,通常是一个整数

【C++】标准流与命名空间简介 ( Visual Studio 2019 中创建 C++ 项目 | iostream 标准流 | std 标准命名空间 | cout 控制台输出 )

文章目录一、VisualStudio2019中创建C++项目二、C++代码编写1、iostream标准流2、std标准命名空间3、cout控制台输出4、代码示例一、VisualStudio2019中创建C++项目打开VisualStudio2019,选择"菜单栏/文件/新建/项目"选项,创建新项目;选择Windows平

【C++】面向对象编程引入 ( 面向过程编程 | 查看 iostream 依赖 | 面向对象编程 )

文章目录一、面向过程编程二、查看iostream依赖三、面向对象编程一、面向过程编程给定圆的半径,求该圆的周长和面积;半径为rrr,周长就是2πr2\pir2πr,面积是πr2\pir^2πr2;使用面向过程的方法解决上述问题,只能是令程序顺序执行,如果要求多个圆的面积,则需要重复执行过程代码;代码示例://包含C++

手撕双链表

>作者简介:დ旧言~,目前大一,现在学习Java,c,c++,Python等>座右铭:松树千年终是朽,槿花一日自为荣。>望小伙伴们点赞👍收藏✨加关注哟💕💕🌟前言前面我们已经学习了顺序表和单链表,顺序表可以存储动态的数据,但是一旦元素过少,而又要开辟空间,这样就造成空间的浪费,而单链表以节点为单位存储,不支持随机

旅游出行类APP如何找到策略优势,最大化流量红利

刚刚结束了暑期出游,中秋国庆小长假马上到啦,出行计划又要安排起来了!多样化的出行方式为大家旅行带来极大的便利,同时,伴随互联网+模式的深化发展,各式各样的旅游出行类APP已经成长为旅行用户所依赖的一类工具。今天我们就来聊聊这类应用如何获利,如何开启商业化之路。旅游出行类APP现状疫情结束与政策扶持带动旅游业强势复苏随着

从金蝶云星空到赛意SMOM通过接口配置打通数据

从金蝶云星空到赛意SMOM通过接口配置打通数据数据源平台:金蝶云星空金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上,提供了标准的管理模式;通过标准的业务架构:多会计准则、多币别、多地点、多组织、多税制应用框架等,有效支持企业的运营管理;K/3Cloud提供了标准的业务建模:35种标准ERP领域模型、1046种

ELK日志分析系统

ELK概述是一套基于Elasticsearch(存储)、Logstash(过滤)、Kibana(前端展示)三个开源工具的日志收集、存储、检索和可视化的解决方案ELK可以帮助用户快速定位和分析应用程序的故障,监控应用程序的性能和安全性,以及提供丰富的数据分析和展示功能Elasticsearch(存储)是一个分布式搜索和分

springboot整合aop,实现日志操作

前言:整合之前,我们要明白aop是什么,为什么要用aop,aop能帮我们做什么。答:AOP是面向切面编程(Aspect-OrientedProgramming)的简称,它是一种编程思想,旨在在面向对象编程(OOP)的基础上进行功能模块的解耦和隔离。在传统的业务处理代码中,通常需要进行事务处理、日志记录等操作,这些操作会

redis深度历险 1 - Redis基础数据结构-001

Redis有5种基础数据结构,分别为:string(字符串)、list(列表)、set(集合)、hash(哈希)和zset(有序集合)。熟练掌握这5种基本数据结构的使用是Redis知识最基础也最重要的部分,它也是在Redis面试题中问到最多的内容。1字符串string字符串string是Redis最简单的数据结构。Re

热文推荐