【C++】STL学习——stack和queue的讲解(了解适配器)

news2024/9/16 11:36:12

目录

  • stack介绍
  • queue介绍
  • 适配器
  • stack的模拟实现
  • queue模拟实现
  • deque(了解)

stack介绍

  1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行
    元素的插入与提取操作。
  2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定
    的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
  3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下
    操作:
    empty:判空操作
    top:获取栈顶元素操作
    push:从栈顶插入元素操作
    pop:从栈顶删除元素操作
  4. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,
    默认情况下使用deque。
  • deque等会会进行介绍。
  • stack参考文档

stack
实际上我们在数据结构初阶时就已经使用过C语言模拟实现过stack(栈)了,具体可移步到——C语言实现栈。由此一文基本可以了解栈的特性及相关操作了。而今天在STL中的stack的实现与我们C语言实现的方式有所区别;stack在STL中并不是划分在容器(Containers) 一栏,而是作为容器适配器(Container adaptors)

queue介绍

  1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端
    提取元素。
  2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的
    成员函数来访问其元素。元素从队尾入队列,从队头出队列。
  3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操
    作:
    empty:检测队列是否为空
    size:返回队列中有效元素的个数
    front:返回队头元素的引用
    back:返回队尾元素的引用
    push_back:在队列尾部入队列
    pop_front:在队列头部出队列
  4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标
    准容器deque。
  • queue参考文档
    queue
    同样,我们也在C语言数据结构学习阶段模拟过队列(queue),C语言实现队列,该文讲解了队列特性及实现。STL中的queue的定位于stack一致;都不是划分在容器(Containers) 一栏,而是作为容器适配器(Container adaptors)

适配器

适配器作为STL的六大组件之一
STL

适配器(Adapters)是一种非常重要的设计概念,它允许通过一种数据结构来修改或增强另一种数据结构的接口或行为。适配器设计模式是面向对象设计中的一种结构型模式,而在STL中,它主要通过模板和继承(有时也使用组合)来实现。STL中的适配器主要包括以下几种类型:

  • 容器适配器 Container Adapters
  • 迭代器适配器 Iterator Adapters
  • 函数适配器 Function Adapters

接下来通过对stack和queue的模拟实现来一并学习容器适配器。

stack的模拟实现

回看stack介绍部分的3,4点:stack作为适配器,其底层结构可以是vector,也可以是list,因为这两个都支持stack的基本操作,所以vectorlist都可以作为stack的底层容器。而库里stack的默认底层容器为deque,这是因为它兼具vectorlist的一些特点,比较适合stack的操作。

stack的实现十分简单,因为它实际上只是另一个容器的套壳,调用的都是底层容器的相关操作。只需要关注stack的定义:第一个模板参数为具体类型,第二个参数为底层的容器,且该容器默认为deque
stack
为了不和库里的stack发生冲突,将模拟实现的stack封在自己的命名空间里。在这模拟实现中你会发现没有默认成员函数;这是因为stack类中只有一个成员,该成员为传入容器的对象,而底层容器早就是实现好的,实例化该对象时会自动调用它的默认成员函数,所以stack不需要再去实现自己的默认成员函数。只需要实现stack的基本操作push pop top empty size,当然这些操作也是不需要手撕的,都是调用底层容器的相关操作。

namespace djs
{
//老方法
//template<class T>
//class stack
//{
//
//private:
//	T* _a;
//	size_t _top;
//	size_t _capacity;
//
//};

//适配器模式:list,vector,deque都可以作为底层容器
template<class T,class Container=deque<T>>
//template<class T,class Container=list<T>>
//template<class T,class Container=vector<T>>
class stack//stack为容器适配器,通过对特定类封装作为其底层的容器
{
public:
	//不需要写默认函数,因为封装了其他类作为底层容器,直接用对应类的就可以
	void push(const T& x)
	{
		_con.push_back(x);
	}

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

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

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

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

private:
	Container _con;//stack的成员为第二个模板参数,默认为deque这个容器
};

queue模拟实现

观察queue的结构发现,它和stack是一样的;两者都为容器适配器,实现逻辑是一致的。
queue
queue的底层容器同样也可以使用list vector deque实现;默认使用deque,因为stack,queue只会在头尾操作,而deque则是非常适合这一模式,所以采用deque作为默认实现的容器。

namespace djs
{
	template<class T,class Container=deque<T>>
	//template<class T, class Container = list<T>>
	//template<class T, class Container = vector<T>>
	class queue//,也为空间适配器,与stack同理
	{
	public:
		
		void push(const T& x)
		{
			_con.push_back(x);
		}

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

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

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

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

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

	private:
		Container _con;
	};

deque(了解)

deque(双端队列)是C++标准模板库(STL)中的一个序列容器,它允许在容器的前端和后端快速插入和删除元素。与vector相比,deque不保证所有元素都存储在连续的内存位置,但它提供了在容器两端进行操作的性能优势。这使得deque成为在需要频繁在容器两端进行操作的场景下的理想选择
双端队列deque

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,可以理解为将数组都当作链表的节点,再将其串起来;所以就造成了有连续但是不完全连续的空间。实际deque类似于一个动态的二维
数组,其底层结构如下图所示:

双端队列的结构

先构造出大小为 N 的小数组(缓冲区),这些小数组是双端队列存储元素的地方。
再构造出一个 map 作为主控数组(通过链式结构链接),数组中元素为数组指针,用来管理一段一段的数组。

deque结构

  • map为一个中控数组(不是STL中的map),用map来管理一个一个连续空间的数组。

双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落
在了deque的迭代器身上,因此deque的迭代器设计就比较复杂
,如下图所示:

deque迭代器

  • cur 指向当前需要的数据位置
  • first 指向 buffer 数组起始位置
  • last 指向 buffer 数组终止位置
  • node 反向指向中控数组

deque的维护

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

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

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

凑巧的是,stack和queue可以避开缺陷,因为 stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作,同时汲取其优点,因此双端队列为容器适配器的默认底层容器。

对于这种中庸且复杂的容器,只需要做简单了解就行了。

介绍,模拟实现两种简单的数据结构,其一般作为容器适配器,底层由别的容器实现。

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

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

相关文章

Java | Leetcode Java题解之第393题UTF-8编码验证

题目&#xff1a; 题解&#xff1a; class Solution {static final int MASK1 1 << 7;static final int MASK2 (1 << 7) (1 << 6);public boolean validUtf8(int[] data) {int m data.length;int index 0;while (index < m) {int num data[index];…

算法练习题18——leetcode240搜索二维矩阵||(二分)

题目描述 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。 代码 class Solution {public boolean searchMatrix(int[][] matrix, int target) {for(int[…

双指针(6)_单调性_查找总价格为目标值的两个商品

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 双指针(6)_单调性_查找总价格为目标值的两个商品 收录于专栏【经典算法练习】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#…

DuPL: Dual Student with Trustworthy Progressive Learning for Robust WSSS

摘要 近年来&#xff0c;具有图像级标签的单阶段弱监督语义分割(WSSS)因其简化了其繁琐的多阶段语义分割而获得了越来越多的关注。由于类激活图(Class Activation Map, CAM)固有的模糊性&#xff0c;我们观察到一级管道经常会遇到由错误的CAM伪标签引起的确认偏差&#xff0c;…

基于SpringBoot的图书馆座位预约系统+小程序+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

继电器的使用

本文为大家讲一下继电器的常规使用. 添加 在菜单中选择 “绘制–无源元件–添加继电器(relay)” 以添加继电器. 或者用 shiftr(大写) 这个快捷键 继电器由一个线圈和该线圈所控制的铁质弹性开关(衔铁)组成. 原理 它的原理如下: 上面的铁质弹性开关, 默认情况下在弹力作用下…

java基础概念22-抽象类

一、抽象类的引入 1-1、封装 问题&#xff1a;javabean越来越多。重复的内容越多——继承 1-2、继承 二、抽象类、抽象方法 一个方法抽取到父类中&#xff0c;不确定方法体——抽象方法 定义了抽象方法的类——抽象类。 在Java中&#xff0c;抽象类是一种特殊的类&#xff0c…

博士生锻炼记录:2024.9.8

读博三年来感觉身体状况大不如前&#xff0c;虽然博士生的主要任务就是做课题和发文章&#xff0c;但是身体健康也是不容忽视的一环&#xff0c;一个好的身体是做好任何事情的基础&#xff0c;我们应该在不影响身体健康的前提下努力做课题。 这周初去参加了一个体成分测量的活…

Python编码系列—Python项目管理:掌握高效工具与实践

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

YOLOv9改进策略【Neck】| 使用CARAFE轻量级通用上采样算子

一、本文介绍 本文记录的是利用CARAFE上采样对YOLOv9的颈部网络进行改进的方法研究。YOLOv9采用传统的最近邻插值的方法&#xff0c;仅考虑子像素邻域&#xff0c;无法捕获密集预测任务所需的丰富语义信息&#xff0c;从而影响模型在密集预测任务中的性能。CARAFE通过在大感受…

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包&#xff0c; 通常我们会使用nohup直接启动&#xff0c;但是还是需要手动停止然后再次启动&#xff0c; 那如何更优雅的在服务器上启动jar包呢&#xff0c;让我…

设计模式之工厂模式(通俗易懂--代码辅助理解【Java版】)

文章目录 1、工厂模式概述1&#xff09;特点&#xff1a;2&#xff09;主要角色&#xff1a;3&#xff09;工作流程&#xff1a;4&#xff09;优点5&#xff09;缺点6&#xff09;适用场景 2、简单工厂模式(静态工厂模式)1) 在简单工厂模式中&#xff0c;有三个主要角色&#x…

基于SpringBoot的宠物服务系统+uniapp小程序+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

浏览器插件利器--allWebPluginV2.0.0.20-alpha版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…

小琳AI课堂:深入学习BERT

大家好&#xff0c;这里是小琳AI课堂。今天我们来聊聊BERT&#xff0c;这个在自然语言处理&#xff08;NLP&#xff09;领域掀起革命风潮的模型。 出现背景 在BERT之前&#xff0c;NLP领域主要依赖RNN或CNN模型&#xff0c;这些模型大多只能单向处理文本&#xff0c;从左到右…

【全网首创】大模型LLM-RAG知识库问答项目实战课

在大数据和人工智能迅猛发展的今天&#xff0c;大模型和知识库的结合成为了理论探索和实际应用的重要方向。LLM-RAG项目课程正是围绕这一热点展开&#xff0c;旨在通过系统性的教学&#xff0c;帮助学员掌握从项目部署、模块开发到实际应用的完整流程。课程共有43课时&#xff…

SprinBoot+Vue公交智能化系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…

高可用架构模式

架构里比较重要的是高性能、高可用、高扩展性。上次是高性能&#xff0c;这次是高可用。 对一般的项目而言&#xff0c;高可用主要用公司提供的基建&#xff0c;如多机房部署、主从等。但有些项目确实需要思考更多高可用的事项&#xff0c;如资源不足的情况下要做好限流或者降…

gdb中使用python脚本

1、入门案例 首先有1个a.cpp&#xff0c;代码如下&#xff1a; #include <map> #include <set> #include <iostream> #include <string>using namespace std;struct MyStruct {std::string mName;std::map<int, std::string> mField1;std::set…

SpringBoot3 简单集成 Mybatis plus

SpringBoot3 集成 Mybatis plus 1、引入Mybatisplus的starter <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version></dependency>2、引入数据…