Deque 的理解 STL中stack与queue为什么选择使用deque为底层模板容器

news2024/11/20 13:43:02

目录

一、Deque的引入

二、Deque是什么?

三、deque的遍历方式?deque的缺陷?

四、它为什么能更贴合与stack与queue?

五、STL中vector与list的底层实现


一、Deque的引入

 Stack、Queue在之前的博客中我也是分别使用了更容易处理的vector和list来实现。

栈是一种先进后出,只能基于一端(栈顶元素)来进行元素访问、修改即各项操作,栈的各项操作使用vector中的一部分接口可以完整的封装起来,将vector中更倾向于stack的一些接口以栈的接口形式给用户呈现出来。例如push、pop均可以使用vector中的push_back、pop_back来进行封装。但是vector的缺陷也比较严重,就是如果插入、删除元素的时候就要进行大量的搬移元素操作。

队列是一种先进先出的数据结构,只能从尾部(队尾)进行插入元素,访问、检索、删除只能从头部(队头)来进行操作,而list链表结构头删尾插功能更加贴合了这一特性。然而list的离散式存储很容易造成内存碎片,空间利用率比较低。

上方的栈和队列都是基于一种容器来进行封装实现,将更贴合于用户需求的接口呈现出来,我们把这种容器成为容器适配器。

而在STL中的栈和队列却是基于一种叫做Deque的容器来进行封装。Deque究竟具有什么功能结构?Deque的实现原理是什么?它为什么能更贴合与stack与queue?

二、Deque是什么?

deque(双端队列)是一种双开口的“连续”的数据结构,可以在其头尾两端进行插入与删除操作,并且时间复杂度都为O(1),它相比于vector不用进行大量的元素搬移,相比于list空间利用率更高。

deque并不是真正连续的一段空间,而是由一段段连续的小空间拼接而成的。

基本原理:新建一块数组,将数组的地址(0x234)存入map中控器中,在数组中尾插的时候就在该块数组中进行尾插,当将这块数组空间存储满了之后,就开辟一块新的数组空间,并将该数组的地址(0x456)放入之前数组的下一个位置,然后在进行尾插。

当头插时,创建一块新数组,并把新数组的地址(0x123)放入map中0x234的上一块位置。然后在新数组的尾部进行插入。

 当map满载之后,将map进行扩容,开辟新空间,拷贝元素,使用新空间,这里的map中存放都是一个个的地址,数组拷贝起来也比较容易。

我的一个小疑问,为什么不使用链表来存储这些数组的地址而是用数组来进行存储呢?

首先,存放的数据是一片片的地址,扩容拷贝时也比较容易,然而使用链表来进行存放地址,链表是使用一块块小的结点来进行存储,这无疑降低了内存的使用率

三、deque的遍历方式?deque的缺陷?

void test()
{
    deque<int> q = {1,2,3,4,5,6,7};
    auto it = q.begin();
    while(it != q.end())
         cout<<*it<<" ";
    cout<<endl;
}

诸如vector、list都能实现下方类似的代码进行遍历访问,那么deque如何进行迭代器访问,上面的deque原理中一块块数组的地址通过中控器map来进行存储,然而在deque的内部迭代器上有着这样的结构:

 iterator中有这cur、first、last、node这几个指针,前三个指针就类似于组成一个vector结构,而node结点就描述了该块数组在map中的存储位置情况。

对于一整块deque的遍历来说,就是从第一个存储空间的第一个frist开始,直到最后一个存储空间的last位置,中途要进行不断的判断,deque的迭代器要不断的进行检测其是否移动到了某段空间的末尾位置,导致效率低下,这也正是deque的致命缺陷

四、它为什么能更贴合与stack与queue?

stack为先进后出结构,所有具有push_back和pop_back的容器都可以作为底层默认容器,比如list,vector。

queue为先进先出结构,所有具有push_back和pop_front的容器都可以作为底层默认容器,比如list。

然而STL库中使用deque作为底层模板容器的原因:

1、deque所有的头删头插尾删尾插的时间复杂度都为O(1)非常的高效,但是致命缺陷就是进行遍历,然而stack与queue根本不需要对元素进行遍历,使用deque作为底层模板容器简直就是取其精华去其糟粕的典型案例。

2、使用vector作为stack的底层模板虽然可以,但是效率低下(插入删除需要对元素进行大量搬移操作),使用deque相比于list作为queue的底层模板更能提高空间利用率。

五、STL中vector与list的底层实现

#include<deque>
namespace bite {
	template<class T, class Con = deque<T>>
	//template<class T, class Con = vector<T>>
	//template<class T, class Con = list<T>>
	class stack {
		public:
			stack() {}
			void push(const T& x) {
				_c.push_back(x);
			}
			void pop() {
				_c.pop_back();
			}
			T& top() {
				return _c.back();
			}
			const T& top()const {
				return _c.back();
			}
			size_t size()const {
				return _c.size();
			}
			bool empty()const {
				return _c.empty();
			}
		private:
			Con _c;
	};
}
#include<deque>
#include <list>
namespace bite {
	template<class T, class Con = deque<T>>
	//template<class T, class Con = list<T>>
	class queue {
		public:
			queue() {}
			void push(const T& x) {
				_c.push_back(x);
			}
			void pop() {
				_c.pop_front();
			}
			T& back() {
				return _c.back();
			}
			const T& back()const {
				return _c.back();
			}
			T& front() {
				return _c.front();
			}
			const T& front()const {
				return _c.front();
			}
			size_t size()const {
				return _c.size();
			}
			bool empty()const {
				return _c.empty();
			}
		private:
			Con _c;
	};
}

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

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

相关文章

【蓝桥杯】历届真题 杨辉三角形 (省赛)Java

【问题描述】 下面的图形是著名的杨辉三角形: 如果我们按从上到下、从左到右的顺序把所有数排成一列&#xff0c;可以得到如下数列: 1,1&#xff0c;1&#xff0c;1&#xff0c;2,1&#xff0c;1&#xff0c;3,3&#xff0c;1&#xff0c;1,4&#xff0c;6,4&#xff0c;1&…

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 (六)多功能数据处理器

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 &#xff08;六&#xff09;多功能数据处理器 &#x1f508;声明&#xff1a; &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN博客 &#x1f9e8;未经作者允许&#xff0c;禁止转载 &#x1f511;系列专栏&#xff1a;牛客…

react基础Day02-受控组件评论案例propscontext

React组件 目标 能够知道受控组件是什么能够写出受控组件了解非受控组件 表单处理 受控组件&#xff08;★★★&#xff09; HTML中的表单元素是可输入的&#xff0c;也就是有自己的可变状态而React中可变状态通常保存在state中&#xff0c;并且只能通过setState() 方法来…

[acwing周赛复盘] 第 86 场周赛20230114

[acwing周赛复盘] 第 86 场周赛20230114 一、本周周赛总结二、 4794. 健身1. 题目描述2. 思路分析3. 代码实现三、4795. 安全区域1. 题目描述2. 思路分析3. 代码实现四、4796. 删除序列1. 题目描述2. 思路分析3. 代码实现六、参考链接一、本周周赛总结 去吃羊蝎子了&#xff0…

基于汽车知识图谱的汽车问答多轮对话系统 详细教程

结果: 1 技术路线 该技术路线主要将KBQA分为三部分,实体识别与实体链接,关系识别,sparql查询,其中每个部分分为一到多种方法实现。具体的处理流程图如下:

大脑的记忆

AI神经网络中的记忆 当前AI发展进入一个瓶颈,大家都意识到还是要继续在人脑中获取AI方向的指引。当然也有科学家说物理世界与心理世界并非一一对应,人类的智能也没必要与物理世界一一对应,甚至本质上都可以是不同的,所以没必要研究大脑认知和大脑的机制,更不需要分子级别…

IDEA structure窗口各标志及功能

文章目录图标对象类型访问权限其他修饰符工具栏图标 对象类型 class 类 interface 接口 enum 枚举 interface 注解 class initializer 代码块 method 方法 field 字段/属性 anonymous class 匿名类 lambda lambda表达式 propertie 访问器&#xff08;get方法&#xff0…

【Java面试】Queue接口

文章目录BlockingQueue中有哪些方法&#xff0c;为什么这样设计&#xff1f;BlockingQueue是怎么实现的&#xff1f;BlockingQueue中有哪些方法&#xff0c;为什么这样设计&#xff1f; 先看一眼结构&#xff0c;再看具体的分析 为了应对不同的业务场景&#xff0c;Blockin…

拉伯证券|业绩猛增超13倍,主力连续抢筹,这只股收获4连板

成绩陡增股获主力接连抢筹 春节日益接近&#xff0c;A股成交活跃度有所下滑&#xff0c;不过有一些股票节前继续取得主力喜爱。证券时报•数据宝核算&#xff0c;到1月12日收盘&#xff0c;沪深两市共54只个股接连5日或5日以上主力资金净流入。 主力资金净流入继续周期最长的是…

人工智能学习07--pytorch03--tensorboard(下载tensorboard、opencv)

transform 主要是对input图像进行变换&#xff08;统一尺寸、对图像中的数据进行类的转换&#xff09; TensorBoard很有用 如&#xff1a;通过loss的变化过程&#xff0c;来看loss的变化是否复合预想。也可以通过loss来选择模型。 TensorBoard&#xff0c;虽然他是TensorFlo…

排序综合(C++版)

目录 排序综合 一、问题描述 二、运行环境说明 三、代码段 四、效果展示 排序综合 备注&#xff1a;大二&#xff08;上&#xff09;数据结构课程设计B题 一、问题描述 给定N…

Python asyncio异步编程简单实现

今天继续给大家介绍Python相关知识&#xff0c;本文主要内容是Python asyncio异步编程简单实现。 一、asyncio事件循环简介 asyncio引入了事件循环的概念。事件循环是一个死循环&#xff0c;还循环会检测并执行某些代码。在Python中&#xff0c;引入了asyncio模块后&#xff…

动态内存管理:学习笔记9

目录 一.前言 二.动态内存函数 1.malloc和free 2.calloc函数 3. realloc函数(动态内存空间调整函数) 情形一&#xff1a;扩容时&#xff0c;原内存地址处可以容纳调整后的动态内存 情形二&#xff1a;扩容时&#xff0c;原内存地址无法容纳调整后的动态内存 三.C/C程序…

MATLAB实现费诺编码的计算与分析

一、实验目的 1、理解霍费诺编码的原理。 2、掌握费诺编码的方法和步骤。 3、熟悉费诺编码的效率。 4、本实验用Matlab语言编程实现费诺&#xff08;Fano&#xff09;编码。 二、实验环境 windows XP&#xff0c;MATLAB 7 三、实验原理 费诺编码算法如下&#xff1a;在信源…

构建前端项目

1.使用vite构建vue项目 vite构建vue项目&#xff0c;输入以下命令&#xff1a; npm init vitelatest接着按照提示的命令选择项目的名称、框架、语言。接着项目就构建完成了。 接着将构建好的项目&#xff1a;vite-demo拖入vsCode里面&#xff0c;在package.json中可以看到项…

redis基础命令使用

目录 Redis redis存储结构&#xff08;KV&#xff09; String string类型介绍 string类型数据的基础操作 string类型数据的扩展操作 List list类型介绍 list类型数据基本操作 list类型数据扩展操作 hash hash类型介绍 hash类型数据的基本操作 hash类型数据扩展操…

傅里叶变换

傅里叶变换 傅里叶变换常用的三个函数 函数一: numpy.fft.fft2: 复数数组 函数二: numpy.fft.fftshift: 将零频率分量移动到频谱中心 函数三: 20*np.log(np.abs(fshift)) 设置频谱的范围 import cv2 import numpy as np import matplotlib.pyplot as pltdef test_1():img cv2…

再说多线程(三)——Mutex类

1.引子在前面2节&#xff0c;我们已经讨论了Lock语句和Monitor类&#xff0c;Locks 和 Monitors 确保 InProcess 线程的线程安全&#xff0c;即由应用程序本身生成的线程&#xff0c;即内部线程。但是&#xff0c;如果线程来自 OutProcess&#xff0c;即来自外部应用程序&#…

Java 诊断利器 Arthas monitor/watch/trace命令

一、监控相关命令介绍 二、监控相关命令 2.1、运行Demo 2.2、monitor 命令 2.2.1、方法监控 2.3、watch 命令 &#xff08;重要&#xff09; 2.3.1、观察函数调用返回时的参数、this 对象和返回值 2.3.2、查看函数调用的入参和返回值 2.3.3、深度遍历 x 说明 2.3.4、查…

检验仪器控制怎么停止的

之前介绍仪器控制启动是按维护的调用M和仪器ID组串直接j启动进程&#xff0c;进程在调用Start启动TCP。 组装执行M串用j启动进程 启动TCP通道&#xff0c;成功之后就到f的死循环了 死循环这里容易有个误解&#xff0c;以为Stop是停止仪器接口的。其实这个Stop是判断要不要…