C++:STL-stack,queue,deque

news2024/11/16 16:45:11

栈和队列

  • 1.栈和队列文档理解
  • 2.为什么没有迭代器
  • 3.Container到底是什么
  • 4.模拟实现源码--使用适配器模式
  • 5.deque
    • 5.1定义
    • 5.2底层结构
      • 头插头删
      • 随机访问
      • 扩容
    • 5.3缺陷
      • 5.4为什么选择deque作为stack和queue的底层容器

1.栈和队列文档理解

在这里插入图片描述
我们通过其上的介绍发现了几个点:

1.这个Container是什么,它后面的缺省值又是什么呢?

在这里插入图片描述
官网中对其的解释为第二个模板参数,那么它到底是什么呢?
在这里插入图片描述

2.stack被称为容器适配器,那么容器适配器又是什么呢?
在这里插入图片描述
3.既然vector,list和deque都可以作为Container,那么为什么默认的就是deque呢?

在这里插入图片描述
4.stack竟然没有迭代器,这是为什么呢?

2.为什么没有迭代器

首先栈和队列没有实现迭代器的原因很简单,因为它们不需要,它们是通过自己的先进先出和先进后出来进行数据操作,并且在遍历时它们需要先获取栈顶或者队头的元素打印后再将其pop出去,而不是像vector那样直接全部遍历。

日常使用:

stack<int> st;
st.push(1);
st.push(2);
st.push(3);
st.push(4);
st.push(5);

while (!st.empty())
{
	int top = st.top();
	cout << top << " ";
	st.pop();
}

3.Container到底是什么

要了解Container是什么,那我们就得明白什么是容器适配器(container adaptor)。

容器适配器是一种设计的模式,它可以实现代码的封装和复用,其可以将一个接口转换成另外一个我们使用的接口。

通俗理解它就是可以兼容传入的所有的合适的容器,作为底层实现的成员。

对于stack的实现,我们可以像list一样在底层封装结点自己实现,但是我们的栈有顺序栈(底层使用vector实现)和链栈(底层使用list实现),那么如果我们底层容器直接选择vector,就会有些死板,链式栈还需要再次实现一个,因此提出了适配器模式:既然vector和list两种容器都可以实现栈,而实现两个栈又很麻烦,那么我们可不可以实现传入对应的容器,让编译器自动适配实现出底层为传入容器的栈呢?

对于使用者 ,只暴漏其使用的接口,如push,pop等,而实现时,push等调用传入容器的对应函数,如果传入的是list,就调用list的为尾插,如果传入的容器是vector,就调用vector的尾插。

4.模拟实现源码–使用适配器模式

//栈的模拟实现
namespace Stack
{
    // 泛型编程--->适配器模式
    // 因为它们的底层既可以使用顺序表,也可以使用链表实现,如果只使用一种实现,就会写死
    // 可以使用模板,因为vector和list在效率上各有好坏,因此库中实现了一个两个都沾点的库函数deque来作为缺省值
    // 缺省模板
    template<class T, class Container = deque<T>>
    // 先进后出
    class stack
    {
    public:
        stack()
        {
            //私有成员变量为自定义类型,调用它的构造
        }

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

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

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

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

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

        void swap(stack& s)
        {
            _c.swap(s._c);
        }
    private:
        Container _c;
        //vector<int> _c;
        //list<int> _c;
    };
}

//队列模拟实现
namespace Queue
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		queue()
		{

		}

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

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

		const T& front() const
		{
			return _c.front();
		}

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

		const T& back() const
		{
			return _c.back();
		}

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

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

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

		void swap(queue& q)
		{
			_c.swap(q._c);
		}

	private:
		Container _c;
	};
}

5.deque

我们知道vector头删尾删的效率非常慢,但是其支持随机访问(使用[ ]来访问),而list头删尾删的效率比较高,但是其不支持随机访问。

而如果使用vector或者list来作为栈和队列的默认容器,都有一些缺点,因此发明了deque容器。

5.1定义

deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。

5.2底层结构

首先,deque的空间并不是真正的连续,如果是真正的连续就无法O(1)实现头尾的插入删除。它的空间是由许多段的空间拼接起来的,可以使用二维数组来理解。

首先其先开辟一个中控器数组,其数组中并不是存储有效值,而是存储指向一段空间的地址,该段空间被称为缓冲区,其最开始存储元素时,不是在中控器的最开始位置来开辟空间来存储数据,而是在中控数组中间位置的缓冲区开始。

头插头删

在中控数组中间位置的缓冲区开始,如果该缓冲区没有满,则直接在该缓冲区位置移动数据插入删除,如果该缓冲区已经满了,则在该缓冲区对应的中控数组前面的位置再进行如上操作,实现头部的插入删除。由于每次都是对缓冲区这一小部分片段来操作,这样就可以不需要移动大量的元素来实现头插头删。

随机访问

deque的随机访问通过其迭代器来实现。deque的迭代器结构如下。其中node指向其在中控器数组中的位置,first和last指向该缓冲区的开头和结尾,cur指向当前已经存储到的位置(即有效位置),如果该缓冲区遍历完成,则可以通过node找到其所在中控器中的位置,再++即可继续找到下一个位置。

扩容

由于其是数组,如果空间存储满了,则需要扩容,deque的扩容只需要重新开好中控器数组的空间,然后将旧的中控器中的存储缓冲区的地址拷贝到新的中控器数组中即可。

在这里插入图片描述

在这里插入图片描述

5.3缺陷

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

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

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

5.4为什么选择deque作为stack和queue的底层容器

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:

1.stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
2.在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。

结合了deque的优点,而完美的避开了其缺陷。

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

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

相关文章

Python分析之3 种空间插值方法

插值是一个非常常见的数学概念,不仅数据科学家使用它,而且各个领域的人们也使用它。然而,在处理地理空间数据时,插值变得更加复杂,因为您需要基于几个通常稀疏的观测值创建代表性网格。 在深入研究地理空间部分之前,让我们简要回顾一下线性插值。 为了演示的目的,我将使…

单链表的基本操作实现:初始化、尾插法、头插法、输出单链表、求表长、按序号查找、按值查找、插入结点、删除结点。

1.参考学习博文&#xff08;写的相当好的文章&#xff09;&#xff1a; http://t.csdnimg.cn/AipNl 2.关于我的总结&#xff1a; 定义单链表&#xff1a; typedef struct LNode {Elemtype data;struct LNode* next; }LNode; data用来存放元素值&#xff0c;next用来指向后…

Vue 项目build打包发布到giteepages ,首页正常显示,其他路由页面报错404的解决方法

直接上解决方法&#xff1a; 打包之后dist上传之后&#xff0c;还要新创一个.spa文件&#xff0c;注意&#xff01;是 .spa 有个. 点&#xff0c;如下图 一般这样就可以开始部署了&#xff0c;然后开启giteepages服务。如果出现了首页正常显示&#xff0c;其他页面显示…

CTFHUB-技能树-Web前置技能-文件上传(前端验证—文件头检查)

CTFHUB-技能树-Web前置技能-文件上传&#xff08;前端验证—文件头检查&#xff09; 文章目录 CTFHUB-技能树-Web前置技能-文件上传&#xff08;前端验证—文件头检查&#xff09;前端验证—文件头检查题目解析 各种文件头标志 前端验证—文件头检查 题目考的是&#xff1a;pn…

第二部分 Python提高—GUI图形用户界面编程(三)

简单组件学习 Radiobutton 单选按钮、Checkbutton 复选按钮和canvas 画布 文章目录 Radiobutton 单选按钮Checkbutton 复选按钮canvas 画布 Radiobutton 单选按钮 Radiobutton 控件用于选择同一组单选按钮中的一个。Radiobutton 可以显示文本&#xff0c;也可以显示图像。 f…

基于XML配置bean(二)

文章目录 1.工厂中获取bean1.静态工厂1.MyStaticFactory.java2.beans.xml3.测试 2.实例工厂1.MyInstanceFactory.java2.beans.xml3.测试 3.FactoryBean&#xff08;重点&#xff09;1.MyFactoryBean.java2.beans.xml3.测试 2.bean配置信息重用继承抽象bean1.beans.xml2.测试 3.…

《系统分析与设计》实验-----在线书店系统 需求规格说明书 哈尔滨理工大学PLUS完善版

文章目录 需求规格说明书1&#xff0e;引言1.1编写目的1.2项目背景1.3定义1.4参考资料 2&#xff0e;任务概述2.1目标2.2运行环境2.3条件与限制 3&#xff0e;数据描述3.1静态数据3.2动态数据3.3数据库介绍3.4数据词典3.5数据采集 4&#xff0e;功能需求4.1功能划分4.2功能描述…

transformer架构详细详解

一、transformer的贡献 transformer架构的贡献&#xff1a;该架构只使用自注意力机制&#xff0c;没有使用RNN或卷积网络。且可以实现并行计算&#xff0c;加快模型训练速度。 &#xff08;将所有的循环层全部换成&#xff1a;multi-headed self-attention&#xff09; 二、t…

Day13-Python基础学习之数据分析案例

数据分析案例 data_define.py # 数据定义的类 class Record:def __init__(self, date, order_id, money, province):self.date dateself.order_id order_idself.money moneyself.province province ​def __str__(self):return f"{self.date}, {self.order_id}, {se…

OpenGL:图元

OpenGL的图元 点 GL_POINTS: 将顶点绘制成单个的点 线 GL_LINES:将顶点用于创建线段,2个点成为一条单独的线段。如果顶点个数是奇数,则忽略最后一个。 顶点:v0, v1, v2, v3, … , vn,线段:v0-v1, v2-v3, v4-v5, … , vn-1 - vn GL_LINE_STRIP:将顶点用于创建线段,…

驱动创新成长,智能费控助力国央企财务数智化升级

如果说中小企业是我国国民经济的毛细血管&#xff0c;那么国央企就是承载着我国市场发展的主动脉&#xff0c;是国民经济的重要支柱。今年以来&#xff0c;面对复杂严峻的国内外发展环境&#xff0c;国央企锚定目标&#xff0c;深入开展提质增效专项行动&#xff0c;打出深化改…

基础算法之二分算法

前言 本次博客&#xff0c;将要介绍二分算法的基本原理以及如何使用&#xff0c;深入浅出 二分可以针对整型以及浮点型接下来对其讲解希望对小白有所帮助吧 整型的二分法 一般要在一个数组中猜出一个数是否存在我们可以遍历一遍整个数组&#xff0c;判断是否存在&#xff0…

python学习笔记B-07:序列结构之列表--列表的常用函数和方法

以xx_函数名(列表名)的形式出现的是函数&#xff1b;以xx_列表名.xx_方法名的形式出现的是方法。 列表常用函数如下&#xff1a; len()&#xff1a;计算列表元素数量 max()&#xff1a;获取列表元素最大值 min():获取列表元素最小值 sum():计算列表中各元素之和 列表常用方法如…

wps导出pdf文献引用不能跳转解决办法

问题描述 本科论文参考文献使用wps设置交叉引用&#xff0c;但导出pdf后无法跳转引用 尝试 用office word打开文件word版跳转没有问题&#xff0c; 另存为pdf或导出pdf。 但是pdf版跳转完全错误。 16跳到14.但是总体而言都是跳到包含该序号的页 要求不高的话也可以&#x…

【WebSocket连接异常】前端使用WebSocket子协议传递token时,Java后端的正确打开方式!!!

文章目录 1. 背景2. 代码实现和异常发现3. 解决异常3.1 从 URL入手3.2 从 WebSocket子协议的使用方式入手&#xff08;真正原因&#xff09; 4. 总结&#xff08;仍然存在的问题&#xff09; 前言&#xff1a; 本篇文章记录的是使用WebSocket进行双向通信时踩过的坑&#xff0c…

链表(C语言)

前言&#xff1a;前面几篇文章我们详细介绍了顺序表&#xff0c;以及基于顺序表来实现的通讯录。今天我们连介绍一下链表的下一个结构链表。那么链表和顺序表究竟有什么区别呢&#xff1f;他们两个的优缺点分别是什么。今天这篇文章就带大家了解一下链表。 目录 一.链表的概念…

新质生产力走红背后,华为云的基本盘和自我修养

文 | 智能相对论 作者 | 沈浪 今年全国两会期间走红的“新质生产力”正成为中国产业转型升级的关键方向。政府工作报告更是把“大力推进现代化产业体系建设&#xff0c;加快发展新质生产力”放在今年政府工作任务的重要位置。 何为新质生产力&#xff1f;简单来说&#xff0…

C++奇迹之旅:探索C++拷贝构造函数

文章目录 &#x1f4dd;拷贝构造函数&#x1f320; 概念&#x1f309;特征 &#x1f320;浅拷贝(值拷贝)&#x1f309;深拷贝 &#x1f320;拷贝构造函数典型调用场景&#x1f320;应用时效率的思考&#x1f6a9;总结 &#x1f4dd;拷贝构造函数 &#x1f320; 概念 在现实生…

web轮播图

思路&#xff1a; 例如&#xff1a;有5张轮播的图片&#xff0c;每张图片的宽度为1024px、高度为512px.那么轮播的窗口大小就应该为一张图片的尺寸&#xff0c;即为&#xff1a;1024512。之后将这5张图片0px水平相接组成一张宽度为&#xff1a;5120px,高度依然为&#xff1a;5…

SpringBoot - Logback 打印第三方 Jar 日志解决方案

问题描述 最近碰到一个很苦恼的问题&#xff0c;就是第三方的 Jar 在自己项目里日志可以正常输出&#xff0c;但是一旦被引用到其他项目里&#xff0c;就日志死活打不出来…… 解决方案 这是原来的配置 - logback.xml <?xml version"1.0" encoding"UTF-8…