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

详解STL中stack_queue为什么选择deque作为默认容器

目录

C语言中的栈和队列

vector和list的区别

deque的底层实现逻辑

1.集vector和list之长

2.双端操作优于vector和list

deque简直是stack_queue的天选容器

为何deque无法完美取代vector和list

相比于vector

1.内存连续性:

2.扩容代价:

3.内存碎片:

相比于list

1.中间操作效率:

2.迭代器稳定性:

不存在“完美容器”,只有“场景适配”


C语言中的栈和队列

当我们对初阶数据结构有所了解之后,就知道栈的底层通常是用顺序表实现,也就是C++的vector,而队列则通常用链表实现,也就是C++的list,详细可以看看博主栈和队列的篇章链接

https://blog.csdn.net/cyzzzuzm/article/details/147747706?fromshare=blogdetail&sharetype=blogdetail&sharerId=147747706&sharerefer=PC&sharesource=cyzzzuzm&sharefrom=from_link

那为什么C++的STL中的栈和队列会选择deque作为默认容器,它相对于顺序表链表的优点又在哪里,它可以完全取代顺序表链表吗?接下来重点讲解这些。

vector和list的区别

vector优点:

1.下标随机访问快,尾插尾删效率高

2.CPU高速缓存命中率高*

vector缺点:

1.头部或中间插入删除效率低下

2.插入时空间要不断扩容,扩容有一定性能损耗*,倍数级扩容可能存在一定的空间浪费

list优点:

1.任意位置的插入删除效率都是O(1)

2.按需申请释放内存,不会存在空间大量浪费的问题

list缺点:

1.不支持下标随机访问

2.CPU高速缓存命中率低*

由此可见,vector和list其实是两个极端,也是功能的极致,一方的有点是另一方致命的缺点,那有没有什么容器能够集两者之长,优缺点折中呢?那就是我们接下来要说的deque容器。

deque的底层实现逻辑

1.集vector和list之长

deque本质上来讲是一个指针数组,数组里面的每一个指针都指向一个buffer数组的位置,也就是说,数组里面连续存放着多个分散在各个空间的buffer数组的地址。它拥有vector的优点吗?当然有,首先是下标访问效率,虽然它的底层多个buffer数组的分布是散乱的,但是遍历完第一个buffer数组之后,指针数组的访问指针就会移动到下一个位置,精准找到第二个buffer数组,然后继续遍历,实现无缝衔接遍历,相当于指针数组将多个buffer数组串联在一起成为一个超级长的数组,大多数情况下,deque的下标访问效率与vector基本一致。前面提到的,它其实就是相当于被拼接起来的一个巨长无比的连续的数组空间,因此CPU高速缓存命中率也很高。但是它的中间插入删除的效率并不高,通常是O(n)级的,这一点和vector类似。list的优点它也并非没有,按需申请释放内存,不会存在空间大量浪费的问题,这一优点类似list,当buffer数组满了之后,会在申请一个内存块,新的指针会挂在指针数组里面,每次申请的内存块大小都是固定的,因此不会有太大的浪费。

2.双端操作优于vector和list

双端操作,也就是头尾的插入和删除,deque的指针数组会在两端预留位置,要双端删除直接删掉双端的buffer数组中的数据即可,效率为O(1),要插入数据,也是插入在双端指向的buffer数组中,如果一个buffer数组满了,比如头部插入,会在开辟一个内存块,它的指针继续存放在指针数组的前端,然后把要插入数据放在新开辟的内存块里,完全不需要移动数据,效率同样O(1)零数据移动,完美降维打击vector,这是优于vector的点,而list还得申请结点(带两个指针的额外内存),内存碎片多,开销更大,而deque一次可以分配多个元素,做到“批量分配”,内存利用率更高,这是优于list的点。最坏的情况,哪怕指针数组也满了,此时可能就要异地扩容,但最多也就是把指针再拷贝到新数组里而已,而且指针占用空间极小,拷贝成本几乎可以忽略,效率极高。综上,双端操作上deque是更优于vector和list的。

deque简直是stack_queue的天选容器

对初阶数据结构有了一定了解之后,我们都知道栈的出入数据是后进先出的(LIFO),从栈顶入数据,同样也从栈顶出数据;而队列,出入数据的原则是先进先出(FIFO),从一头进再从另一头出。我们可以发现,栈和队列无论是出数据还是入数据都是从两端操作的,那么双端操作,我们是不是拥有了可以完美替代vector和list的容器?那就是deque双端队列,因此用它作为栈和队列的默认容器简直再合适不过了

为何deque无法完美取代vector和list

首先我们知道deque兼顾两者的优点,虽全能,却也全不精,没有二者的优点那么极致

相比于vector

1.内存连续性:

vector的元素在内存中是完全连续的,而deque是由多个分散的“内存块”组成,这会造成哪些劣势呢,首先vector的随机访问是真正的O(1),直接通过首地址+偏移量计算,deque虽然也支持随机访问,但是底层实现上需要先计算元素在哪个内存块,再找块内的偏移量,实际效率略低(尤其是数据量巨大时),且vector的CPU缓存命中率更高(连续内存适合CPU预读),遍历速度通常比deque快。

2.扩容代价:

vector虽然扩容时需要整体迁移数据,代价略高,但是一旦扩容完成,后续尾插的效率极高,deque虽然不需要整体迁移数据,但是每次新增内存块时,需要维护指针数组(比如需要扩容指针数组),且小块内存的管理成本更高。

3.内存碎片:

deque有多个内存块,会导致产生更多的内存碎片,而vector是一大块连续的内存,利用率更高。

相比于list

1.中间操作效率:

list的中间插入删除操作只需要改变前后结点的指针,效率很高,纯O(1)操作,而deque的插入删除操作需要移动插入点之后的所有数据,类似于vector,时间复杂度是O(n),而且由于deque内存块分散,移动数据时需要跨越多个内存块,效率甚至比vector更低。

2.迭代器稳定性:

list的迭代器在插入删除操作后,除了被删除的迭代器,始终有效;而deque在头尾插入删除时,迭代器可能会失效(如触发指针数组扩容),中间操作则会导致大量迭代器失效,使用更麻烦。

不存在“完美容器”,只有“场景适配”

vector:适合频繁随机访问、尾插尾删为主的场景,如储存大量数据并遍历。

list:适合频繁中间插入删除的场景。

deque:适合双端频繁操作,但很少中间修改的场景,如实现栈和队列的底层容器。

http://www.dtcms.com/a/422822.html

相关文章:

  • ubuntu下AstrBot +NapCat QQ机器人
  • 新天力:食品容器领域的领军先锋正式开启资本市场新征程
  • iOS 不上架怎么安装?多种应用分发方式解析,ipa 文件安装、企业签名、Ad Hoc 与 TestFlight 实战经验
  • 郑州网站运营沥林行业网站建设
  • 算法面试(6)------mAP 是什么?如何计算?P-R 曲线怎么看?
  • 企业网站推广可以选择哪些方法?系统定制
  • 深度学习--行人重识别技术(超分辨率网络+ResNet101)附数据集
  • CS50ai: week2 Uncertainty我的笔记B版——当 AI 开始“承认不确定”
  • 泉州网站建设开发怎么制作h5棋牌软件
  • 深入Spring Boot生态中最核心部分 数据库交互spring-boot-starter-data-jpa和Hibernate (指南五)
  • 如何使用Python实现UDP广播
  • ThinkPHP 入门:快速构建 PHP Web 应用的强大框架
  • 系统架构 从_WHAT_走向_HOW_的锻造之路
  • UNIX下C语言编程与实践6-Make 工具与 Makefile 编写:从基础语法到复杂项目构建实战
  • 事业单位网站模板网站开发png图标素材
  • 电子商务网站建设外包服务p2p理财网站开发框架
  • Gateway 集成 JWT 身份认证:微服务统一认证的实战指南
  • C语言数据类型与变量详解
  • 【开题答辩全过程】以 php厦门旅游信息网站管理系统开题为例,包含答辩的问题和答案
  • 《重构工业运维链路:三大AI工具让设备故障“秒定位、少误判”》
  • 大模型的第一性原理考量:基于物理本质与数学基础的范式重构
  • Ubuntu 系统安装 Prometheus+Grafana(附shell脚本一键部署↓)
  • Airbnb内部核心键值存储系统 Mussel 已完成从 v1 到 v2 的重构升级
  • 漳州做网站配博大钱少awordpress国内网站吗
  • 在用户调研中应用卡尔曼滤波:用动态思维重构认知更新
  • [免费]基于Python的在线音乐网站系统(后端Django)【论文+源码+SQL脚本】
  • 网站建设后期出现的问题手机网站开发前台架构
  • 首饰设计网站大全如何选择昆明网站建设
  • MapDistill:通过相机 - 激光雷达融合模型蒸馏提升高效基于相机的高清地图构建性能
  • 安卓开发---在适配器中使用监听器