当前位置: 首页 > news >正文

[c++进阶(九)] STL之deque深度剖析

1.前言

本章重点

本章将会着重的介绍deque底层到底是如何实现它能够双向进出的,并且双向进出的消耗率还特别低,并且讲解deque的优缺点。

2.deque的使用

如果没有看我前面两篇文章的,请先看前面两篇文章再来看这篇文章,可以有助于理解。

[c++进阶(八)]STL容器适配器之queue-CSDN博客

[c++进阶(七)]STL容器适配器之stack-CSDN博客

deque在stack和queue里面使用的是deque作为底层容器,但是为何用的是deque呢?他有什么优势呢?又有什么缺点呢?

3.deque的原理

1.deque的结构

deque的底层结构是双端队列,这种队列可以实现双开口进出,并且进出的时间复杂度为0(1)。

与vector相比:头插的更加方便

与list相比:空间连续,空间利用率更高。

2.deque的底层结构

(1)deque的底层空间

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成,实际deque类似于一个动态的二维数组,其底层结构如下:

中控指针数组中存放的是指向缓冲区buffer的指针,是动态开辟的二维数组,先malloc一个指针数组,指针数组的每个位置存放一维数组buffer的地址。当deque不断开buffer时,map中控指针数组满了,那么会增容,不过map增容的代价非常低,因为只需要拷贝存储数据的buffer数组的指针,不需要拷贝buffer中的内容。

如果要计算要访问的元素在第几个buffer里面,每个buffer固定大小,i/buffer.size()+1算出在第几个buffer中,i%buffer.size()算出是buffer中的第几个元素。

(2)deque是如何支持随机访问

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

first指向buffer的第一个位置,last指向最后一个位置,cur指向当前buffer中存在的数据,node则需要回指导中控指针数组。

为什么要指回呢?这是因为当迭代器遍历到当前为止时,如果需要++或者--,自己是无法找到下一个buffer在那个位置,必须根据中控指针的指向找到下一个需要遍历的位置,所以说需要一个node来回指中控指针,方便迭代器迭代。

(3)deque迭代器

那deque是如何借助其迭代器维护其假想连续的结构呢? 如果一个buffer走完了,如何走到下一个buffer的位置呢?用node++来控制,node反向指向map当中当前buffer的位置,那么node++就指向下一个node的位置,解引用就是下一个buffer的位置。

node并不是从第一个位置就开始存放的,从中间开始存放,那么头插就还有空余位置。

而在buffer中存放位置一般都是从尾部开始存放的,这样就方便后续的头插头删,尾插尾删等相关操作了。

3.deque的缺陷

deque不适合随机访问,不适合中间插入和删除函数。可以说他结合了vector和list的相关特性。

可以说deque的优缺点也和vector和list的优缺点息息相关。

(1)deque的致命缺陷

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

(2)deque的优点

① 与vector比较:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是必vector高的。
② 与list比较:其底层是连续空间,空间利用率比较高,不需要存储额外字段。

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作为底层默认容器,不仅效率高,而且内存使用率高。

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 设计模式七大原则
  • leetcode热题100.最长回文子串(动态规划解法)
  • 算法打卡:第十一章 图论part05
  • 基于jsonpath的JSON数据查找
  • linux安装nginx+前端部署vue项目(实际测试react项目也可以)
  • vue-入门速通
  • Java基础知识扫盲
  • 【ppt2svg svg2png/jpg】ppt转图片解决方案
  • [Linux]用户管理指令
  • openai最新o1上线(2024年09月12日)
  • 研1日记15
  • PHPStorm如何调整字体大小
  • 网络信息传输安全
  • 1.《DevOps》系列K8S部署CICD流水线之部署K8S集群~version1.28.2
  • Qt_事件的介绍
  • python3.6+scrapy+mysql 爬虫实战
  • 07.Android之多媒体问题
  • 0基础学习移动端适配
  • Asm.js的简单介绍
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • python学习笔记-类对象的信息
  • Travix是如何部署应用程序到Kubernetes上的
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 订阅Forge Viewer所有的事件
  • 多线程事务回滚
  • 基于组件的设计工作流与界面抽象
  • 技术:超级实用的电脑小技巧
  • 开源SQL-on-Hadoop系统一览
  • 前端工程化(Gulp、Webpack)-webpack
  • 设计模式 开闭原则
  • 无服务器化是企业 IT 架构的未来吗?
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • # Redis 入门到精通(八)-- 服务器配置-redis.conf配置与高级数据类型
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #单片机(TB6600驱动42步进电机)
  • (02)Hive SQL编译成MapReduce任务的过程
  • (day6) 319. 灯泡开关
  • (leetcode学习)236. 二叉树的最近公共祖先
  • (php伪随机数生成)[GWCTF 2019]枯燥的抽奖
  • (补充):java各种进制、原码、反码、补码和文本、图像、音频在计算机中的存储方式
  • (二)pulsar安装在独立的docker中,python测试
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (九)One-Wire总线-DS18B20
  • (七)glDrawArry绘制
  • (十六)一篇文章学会Java的常用API
  • (详细文档!)javaswing图书管理系统+mysql数据库
  • (一) 初入MySQL 【认识和部署】
  • (转)Oracle 9i 数据库设计指引全集(1)
  • (转)Unity3DUnity3D在android下调试
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • ***详解账号泄露:全球约1亿用户已泄露
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...