C++ 容器 deque(双端队列)

news2024/12/24 2:17:12

我们在学习之前的数据结构链表和顺序表的时候,发现顺序表插入删除慢,但是下标查找等速度快,链表下面查找等速度慢,但是插入删除快。它们互补。

那么我们是否可以将两个数据结构结合起来,产生一个完美的数据结构呢?

那么就有一个结合了链表、顺序表两中数据结构的数据结构交双端队列,我们来看看它是否完美:

双端队列deque

从名字来看,它肯定擅长两端的操作。如下图,

结构介绍

同时它还能支持下标的访问,这是和链表大不相同的。那么既然能支持下标访问,肯定就有循序表的结构。我们来看看它具体的结构图:

它的结构和我们自己手动堆区申请的二维数组很像:

有一个二阶指针数组(map数组)存放一维数组的指针,然后模拟二维数组。而deque的结构为一与二维数组不同的就是deque的map数组是从中间开始存的。

下标访问

它的下标访问也就可以很快,例如我们要访问第N个数据,我们假设每组数据的长度是len,那么就是要访问N/len组数据,访问这组数据的第N%len个数据

前插和尾插

如果我们要进行前插,空间够就从后往前插数据;空间不够了,我们就可以往前开辟一个len长的数组,然后从这个数组末尾往前插入数据。

如果我们要进行尾插,空间够就往后插入数据;空间不够了,同样是开辟len长的数组,然后从前往后插入数据。

扩容

如果我们中央数组map有一边的空间不够了,那么就要扩容,然后继续保证两边都有空间。

它的扩容也不是很耗时,大量的数据是存在我们的一维数组里面的,我们只要拷贝一维数组的指针就行了。

结构的局限性

它的结构局限性很明显

一、中间的插入很慢,而且中间的数组都是满的,你里面再插一个数据,后面的就要挤到下一个数组里面去,下一个数组的数据就要依次挤直到挤到边上一格。所以中间插入耗时且复杂

二、它的下标访问也比数组的下标访问慢了几倍。例如我们要进行数组的排序这种需要很多次下标访问的操作,那么就会有很多次的计算,相对耗时一点。但是比链表还是快不少。

STL的deque相关函数介绍

首先是构造函数的介绍。

构造函数

其实只要是学了前面string、vecotr、list就可以发现,它们的构造函数类型都是那六个:默认、带参、迭代器、拷贝、右值引用、初始化设定项列表构造

那我就不多进行介绍了,这里面的内存池我先不介绍,后面统一出一期进行讲解。

我以举例来看这几个构造函数的实现:

析构函数

析构函数大概要释放我们的一维数组和map,系统自动在这个实例化deque类生命周期结束后调用。

operator=

赋值重载函数:

其实可以只用写第一个就行,下面的编译器会通过对应的构造函数隐式类型转换成第一个,然后用它赋值,版本较高的编译器会直接优化成对应的构造。但是我们如果写了这个可以保证在每个编译器版本下都有相同的运行速度。

迭代器相关函数

这都不用再说了吧,还不会的读者可以看这一篇博客:c++迭代器的介绍-CSDN博客

空间操作的函数

szie

size就是返回当前数据的个数

max_size

就是返回size_t形式的-1、

resize

重构数据大小到n

如果比原size小就缩到n这么大,删除的方式是尾删。

如果比原size要小就用val值来扩容,val可以是缺省参数默认给T(),要么是自己传val值。

可以通过下面的例子来看:

empty

判断容器是否为空。

shrink_ti_fit

我们看到上面map是有多余空间的,这个函数就是将多余空间去掉

数据操作函数

operator[]

重载的下标访问,返回引用让我们可以直接操作对应的数据。

at

它和operator[]是一个意思,这是上面的assert报错,这个则抛异常

front

返回第一个数据的引用

back

返回最后一个数据的引用

修改类函数

assign

就是重新给容器值覆盖之前的内容。

push_back

尾插

push_front

头插

pop_back

尾删

pop_front

头删

insert

定点从它前面插入,我们用迭代器来定点,然后插入的内容可以当做是新的一个deque内容,所以支持了5种函数(除了默认),和构造函数差不多

erase

定点删除,或者定区间删除。

swap

交换两个deque容器的内容

clear

清除数据

下面三个是用右值引用实现的插入,在某些情况下速度快于普通的插入

emplace

emplace_front

emplace_back

全局且和deque相关的函数

第一个就是逻辑运算符重载函数

应该没有什么多说的

第二个是全局的实例化swap,因为在函数参数匹配的情况下,实例化的swap优先于模板swap。防止用模板swap(会有中间变量产生)耗时。

deque的自我实现

首先我们知道了中间插入删除的复杂,所以平时大家也不会用这个,毕竟耗时,所以这里我也不实现了。

主要实现一下两边的插入删除操作。

这个容器是目前我实现的最复杂的了,不仅迭代器复杂,而且本体也复杂。

成员变量介绍

首先我们来看本体成员变量有哪些:

本体是由两个迭代器掌管始末节点,然后map掌管主数组的指针,map_size记录map的长度。

我们再来看看迭代器的成员变量

迭代器成员变量有当前一维数组的头指针begin和尾指针end,还有当前指针cur,同时有指向当前一维数组的指针node。还有个room_capacity常量是一维数组的固定长度。

首先我们来看迭代器的实现:

deque_iterator

首先我重命名了T*和T**,方便理清逻辑。

然后是构造函数我这里只写了三个,足够了:

构造函数

默认构造不比多说,全部指向空就行了。

拷贝构造其实都可以不用写,因为和编译器默认的浅拷贝是一样的。

第三个带参构造是给一维数组指针val和当前所在指针n(cur)实现初始化。

val可以确定begin、end以及node,cur就由n直接给。

这里还有析构和赋值,因为我们的参数都不涉及堆区内存,所以直接交给编译器就行了。

然后我们实现加减操作

操作符重载

这里我们可以先实现set_node,就是让node从当前位置往后或者前移动n位并改变begin和end

那么这里的+=和-=操作就好实现了

首先这里的if是防止输入负数的情况,我们直接调用对应的operator。

其次这里的x是我们要往前或者往后移动的距离,因为我们往里面push或者pop后,指针不一定会在起始或者末尾,所以我们可以把它当作在其实或者末尾来看,并加上对应的长度,方便我们计算。

这里我们还发现我的-=的x后面有备注,是当时自己琢磨实现的时候被坑了。如果没有-1就会在某些情况是10,下面的set_node就会跳转,但事实上我们不用跳转。

这里其实逻辑上并不难,但是实现是有点看细节的,大家可以不用看我的代码自己去实现一下。

后面的-、+、++、--都是直接复用我们的+=和-=的。

这里我要提一个小问题,我能否先实现operator+,operator-然后复用-=、+=呢?

理论上我们是可以的,但是有一些细节问题:

我们实现+、-的时候,是一定会创建拷贝的,并用它作为返回值。所以我们用+、-来复用+=和-=都会产生拷贝。而我们直接实现+=和-=是不需要创建临时变量的。

所以我们还是实现+=、-=来复用+、-而不是反过来。否则会增加我们的拷贝。

这里其实拷贝还好只是浅拷贝,但是这个问题不局限与此,比如我们string就用+=和+,string的拷贝是深拷贝,使用多了是很耗时的。

接下来是其他的操作符重载。应该是可以看得懂的

第一个我用的是累加来查看两个迭代器之间相隔了多少数据,其实有更加简单的,这里我就懒得写了。

这里我还有值得提示的重要点就是:

我们的deque成员变量是iterator类型的,如果我们创建const deque类,那么就会让所有成员变量变成const的,那么就会有const iterator的start和finish变量,但是我们实际需要的是const_iterator的start和finish,那么会在下面这个代码中出问题:

编译器就会因为无法从const iterator转变为const_iterator而报错,这个时候我们就要用到隐式类型转换,支持相应的隐式类型转换就要对应的构造函数,所以我们还要写一个对应的构造函数:

这样就会从const iterator转变为const_iterator。

deque

deque唯一比较复杂的就是扩容,但是原理是简单的,大家可以自己试试。

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

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

相关文章

LangChain与Elasticsearch向量数据库的完美结合

在过去的一年中,生成式 AI (Generative AI) 领域取得了显著的进展。许多新的服务和工具应运而生。其中,LangChain 已成为构建大语言模型 (LLM) 应用程序(例如检索增强生成 (RAG) 系统)最受欢迎的框架之一。该框架极大地简化了原型…

【网络安全】通过设备ID绕过双因素身份验证

未经许可,不得转载。 文章目录 正文正文 某站点登陆界面如下所示:https://redacted.com/login 输入正确的用户名密码并拦截登录请求,请求包如下: POST /api/authentication/login-2fa HTTP/1.1 Host: redacted.com Content-Length: 100 Sec-Ch-Ua: "Not)A;Brand&quo…

(南京观海微电子)——投影仪原理及使用介绍

投影仪 是一种用来放大显示图像的投影装置。目前已经应用于会议室演示以及在家庭中通过连接DVD影碟机等设备在大屏幕上观看电影。在电影院,也同样已开始取代老电影胶片的数码影院放映机,被用作面向硬盘数字数据的银幕。 投影仪的成像原理 首先&#xff…

这款新的 AI 工具会消灭 ChatGPT 吗?

随着大型语言模型 (LLM) 的出现,ChatGPT迅速成为全球计算机用户的家喻户晓的名字。这款由 OpenAI 设计的深度学习聊天机器人以知识宝库而闻名——一部互联网百科全书。 继ChatGPT的脚步之后,许多其他生成式AI工具也纷纷涌现。 2023 年 3 月,一…

大型、复杂、逼真的安全服和安全帽检测:SFCHD数据集和SCALE方法

智能守护工地安全:SFCHD数据集与SCALE模块介绍 在人工智能(AI)技术飞速发展的今天,其在建筑工地安全领域的应用正逐渐展现出巨大潜力。尤其是高风险行业如化工厂的施工现场,对工人的保护措施要求极为严格。个人防护装…

07、stm32外部中断

一、配置 二、代码 /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ uint8_t keyFalg 0; // 1按键被按下 /* USER CODE END PD *//* USER CODE BEGIN 4 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {if…

GStreamer 简明教程(三):动态调整 Pipeline

系列文章目录 GStreamer 简明教程(一):环境搭建,运行 Basic Tutorial 1 Hello world! GStreamer 简明教程(二):基本概念介绍,Element 和 Pipeline 文章目录 系列文章目录前言一、静…

windows11怎么加密?如何对win11系统文件进行加密?

“昔者,有物藏于室,恐人窥之,必施锁钥以护之。今之世,信息如海,数据若金,保护之责,重于泰山。Windows 11,微软之新篇,亦需加密之术,以护数据安全。” 本文将…

Golang | Leetcode Golang题解之第341题扁平化嵌套列表迭代器

题目: 题解: type NestedIterator struct {vals []int }func Constructor(nestedList []*NestedInteger) *NestedIterator {var vals []intvar dfs func([]*NestedInteger)dfs func(nestedList []*NestedInteger) {for _, nest : range nestedList {if…

期末速成复习资料——操作系统

体型:选择20判断10填空10*2简答4*5计算2*10 第一章 在一个计算机系统中,通常都含有多种硬件和软件资源。归纳起来可将这些资源分为四类:处理机、存储器、I/O设备以及文件(数据和程序)。相应地,OS的主要功能…

html中的<base>标签和 href属性的使用

先截图一个菜鸟教程的案例 说白了就是将本页面所有的URL前边都加上base标签后边的href中的内容即:

财务会计与管理会计(八)

文章目录 电商绩效工资计算IF函数的应用 参数表的格式转换INDEX、MATCH函数的应用 巧妙计算计件工资引出问题调整方案增加变量扩大范围 智能值班表VLOOKUP函数的使用方法 按照设备类别自动编号VLOOKUP、COUNTIF、TEXT函数的使用方法 多公司多月份损益汇总表OFFSET、INDIRECT函数…

154 · 正则表达式匹配

链接:LintCode 炼码 - 更高效的学习体验! 题解: class Solution { public:/*** param s: A string * param p: A string includes "." and "*"* return: A boolean*/bool isMatch(string &s, string &p) {// w…

Unity求向量和平面的交点

已知条件:平面P的法向量,平面上的一点P0,直线L的方向向量,直线上的一点L0 公式推导: 主要是两点: 1.目标点T在直线上:TL0D*(D未知) 2.目标点T在平面上,则T…

Kubectl 常用命令汇总大全

kubectl 是 Kubernetes 自带的客户端,可以用它来直接操作 Kubernetes 集群。 从用户角度来说,kubectl 就是控制 Kubernetes 的驾驶舱,它允许你执行所有可能的 Kubernetes 操作;从技术角度来看,kubectl 就是 Kubernetes…

【JavaEE】一文学会如何使用:文件IO操作(详解)

目录 前言 什么是IO? IO流原理 IO流分类 InputStream字节流输入 文件输入流--FileInputStream 理解InputStream中的read方法 关闭文件操作 利用Scanner进行字符获取 OutputStream字节流输出 文件输出流--FileOutputStream 理解OutputStream中的…

计算机毕业设计选题推荐-在线学习平台-Java/Python项目实战

✨作者主页:IT研究室✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

Linux - 权限

文章目录 一、用户二、文件 一、用户 1、Linux下有两种用户:超级用户(root)、普通用户。 超级用户:可以再linux系统下做任何事情,不受限制 。 普通用户:在linux下做有限的事情。 超级用户的命令提示符是“…

Python数据分析实战:从零开始构建销售预测模型

随着大数据时代的到来,数据分析已经成为企业决策的重要依据之一。Python作为一种强大的编程语言,在数据分析领域有着广泛的应用。本文将通过一个具体的案例——销售预测——来演示如何使用Python进行数据预处理、特征工程、模型构建与评估。无论你是Pyth…

【持续更新】Adoobe Afteer Effeects 2024 v24.5.0.052最新免费修改版

利用Adoobe Afteer Effeects CC,您可以轻松打造生动的动画标题、字幕以及下三分屏元素。无论是从零开始还是借助应用内丰富的预设动画,都能让您的文字以各种方式动起来,无论是旋转、滑动或是平移,创意无限。 将视频和图像融合在一…