C++之deque

一、vector与list的优缺点

  • vector的优点:下标的随机访问,尾插,尾删效率高。CPU高速缓存命中率高
  • vector的缺点:扩容(效率,空间浪费),不适合头插头删。

连续的物理空间为他带来了优点也带来了缺点,可谓成也萧何败也萧何

  • list的优点: 按需申请和释放空间,任意位置O(1)的插入删除
  • list的缺点:不支持下标的随机访问       

那有没有一种容器既有vector的优点又有list的优点呢,于是deque被大佬们研究出来 。

deque 叫做双端队列,但是它不是队列。它设计的初衷是融合vector和list的优点,组成一个全新的容器,大有替代vector和list的趋势。

二、deque的简单介绍

1.deque的接口

不能看出,从它的接口角度就可以看出它想要替代掉vector和list。但是它失败了,因为它四不像,vector和list在它俩的优点方面做到了极致。deque是啥都会一点,但是不精通。

但是deque 也不是完全没用,栈和队列用它刚刚好。或者有时候你既要头插头删,尾插尾删,又随机访问的时候用它也挺好。

2.deque的原理介绍

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

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

deque这一段段连续的空间就叫做buffer,假设一个buffer里放8个数据就满了,满了以后我就扩容,我再去找一个buffer,物理上虽然不是连续的,但逻辑上他俩是连续的。头插的话,我还是再开上一个buffer,这样就解决了vector的头插和尾插,及空间连续的问题。

然后还设计了一个中控指针数组进行管理这些buffer,比如我开第一个buffer的时候,把这个buffer的指针存在中间位置,头插就在前面位置存一个buffer的地址,尾插就在它后面存一个buffer的地址

如何支持随机访问呢?

假设每个buffer里是8个数据,进行deque[i]操作的时候,首先看i是不是小于第一个buffer的值,如果大于就进行/看是在第几个buffer里,然后%8看是在buffer里的第几个值,进行判断越界。所以这个随机也不是很随,因为他要进行很多的运算。所以如果要频繁的调用[]就不太好了,但是比起list有比较好。

而且deque在中间位置进行插入和删除也很麻烦,且栈和队列也不需要在中间位置进行插入与删除

deque 是如何借助其迭代器维护其假想连续的结构呢?

中控的指针数组的迭代器里有四个指针,两个指针指向指针的开始和结束一个指针指向当前访问的位置,迭代器++就是cur++,当cur等于last的时候就结束,解引用迭代器就是取cur这个位置。当cur等于last结束时跳转下一个buffer的时候,就通过这个node指针,node存储的是指针数组的地址,对node++就找到下一个位置了,也就是下一个buffer。

3.deque的缺陷

vector 比较 deque 的优势是:头部插入和删除时, 不需要搬移元素,效率特别高 ,而且在 扩容时,也不 需要搬移大量的元素 ,因此其效率是必 vector 高的。
list 比较 ,其底层是连续空间, 空间利用率比较高 ,不需要存储额外字段。
但是, deque 有一个致命缺陷:不适合遍历,因为在遍历时, deque 的迭代器要频繁的去检测其是否移动到 某段小空间的边界,导致效率低下 ,而序列式场景中,可能需要经常遍历,因此 在实际中,需要线性结构 时,大多数情况下优先考虑 vector list deque 的应用并不多,而 目前能看到的一个应用就是, STL 用其作 stack queue 的底层数据结构

4. 为什么选择deque作为stackqueue的底层默认容器

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 的效率高 ( 扩容时不需要搬移大量数据,浪费空间也不多 ) ;stack中的元素增长时,deque相比list,cpu高速cache命中。其次不会频繁申请小空间。申请和释放空间次数少,代价低。在queue的元素增长时,同样相比list,cpu高速cache命中。其次不会频繁申请小空间。申请和释放空间次数少,代价低。
所以deque作为stack和queue的默认容器是完胜的。

 

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
dequeC++标准库中的一种容器,它是双端队列的意思。双端队列是一种可以从队列的前端和后端进行插入和删除操作的数据结构。在C++中,deque可以存储任意类型的数据,并且支持动态大小调整。deque中的元素可以通过普通迭代器、常量迭代器和逆转迭代器进行访问。 在deque中,元素的添加和删除操作可以在队列的前端和后端进行,并且插入和删除的时间复杂度都是O(1)。 在C++11中,可以使用emplace_back和emplace_front函数来在deque的尾部和头部插入元素,这些函数可以直接在已有的元素上构造对象,而不需要进行拷贝或移动操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C++ Deque的使用](https://blog.csdn.net/weixin_42587961/article/details/100305841)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [deque容器](https://blog.csdn.net/m0_46376834/article/details/117335026)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值