STL之deque解析

1、deque和vector比较
vector是单向开口的连续线性空间,而deque是双向开口的连续线性空间,也就是说可以在头尾两端做插入删除操作。虽说vector也可以在头部增加元素比如使用insert(begin(),1),但是效率很低涉及到移动元素以及一些移动的细节。
在这里插入图片描述
deque和vector最大差异在于两点:
1、deque可以实现常数复杂度的头部插入删除操作;
2.deque没有所谓的容量概念,因为它是动态地以分段连续空间组合而成。随时可以增加一段空间并组合起来。所以不会出现vector那样空间不足重新配置一块更大的空间。
另外:
虽然deque也提供了随机存取指针,但deque的迭代器不是普通指针,其复杂度和vector不可一道而计。所以除了特殊情况,我们应尽可能使用vector而非deque.对deque的排序操作,我们可以先把其中的数据复制到vector中,利用sort算法排序后,再复制回deque.

2、deque的中控器
deque是连续空间(逻辑上来看)。这我们就会想到array,vector这种连续线性空间。array不能动态增长,而vector的动态增长只是假象,当空间不够时,vector实际是寻觅一块更大的空间,将原数据复制过去,释放原空间。这么做的代价其实很大(虽然每次vector配置新空间会两倍复制,缓解了这个问题)。不过关于为什么是两倍,不是1.5倍,3倍呢,这里面其实有些东西的。先不说了。

deque是由一段一段的定量连续空间组合成。所以deque最大任务是维护整体连续的假象,并提供随机存取的接口。这避开了“重新配置,复制,释放”的三部曲,代价则是更加复杂的迭代器结构和数据结构设计。

deque采用一块所谓的map(不是STL中的map容器)作为主控。map是一小块连续线性空间,其中每个元素是一个指针,指向另一段较大的连续线性空间,称为缓冲区。缓冲区才是真正的存储主体。STL允许指定缓冲区大小,0代表默认大小512字节。
在这里插入图片描述
我们其实可以发现,map内容其实就是一个双重指针,他本身是一个指针,指向的缓冲区也是一个指针,指向一块空间。
在这里插入图片描述

3、deque的迭代器

deque分段连续的空间,为了维持整体连续的假象,这个任务就落在了迭代器operator++,operator–两个运算子身上。
迭代器应该有这样的功能:1、知道缓冲区在哪里;2、判断自己是否处在缓冲区边缘,如果是,那么前进后退一个元素就要跳跃缓冲区。下面是时间方式:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们可以很清楚的发现,deque的迭代器结构比较复杂,里面必须包含缓冲区头部尾部现存和管控map的指针。
在这里插入图片描述
看一个源码++运算的例子,需要判断是否到缓冲区尾端。其他的运算符也可以是类似的思想。

4、deque的数据结构和内存管理
它必须有一个指向map的指针,start,finish两个迭代器,以及map 大小,一旦map不够,就要配置一块更大的map.
在这里插入图片描述
map最少八个节点,最多为缓冲区数目+2,前后各预留一个节点;
要注意,start,finish两个迭代器指向的是第一个缓冲区第一个元素和缓冲区最后一个元素。但是第一个缓冲区并不是Map的第一个节点,最后一个缓冲区也不是map最后一个节点,而是map中间的两个节点。源码中表示为:
在这里插入图片描述

那么什么时候会引起缓冲区的重新配置呢?
1、对于push_back操作,如果最后的缓冲区尚有一个以上的空间,我们就直接在该缓冲区后构造元素;但是如果最后的缓冲区已经没有空间或者只剩一个空间,就会引起配置一块新的缓冲区,然后安置新元素内容,最后改变迭代器finish状态。
对于push_front操作,道理类似,当第一个缓冲区没有备用空间,即start.cur=start.first,就会引起配置一块新的缓冲区,start迭代器状态改变。

以上的操作,都没有涉及到map的重新设置,因为map够用。 如果Map不够了(指的是push_back,push_front扩充缓冲区失败时),分为两种情况:
1、如果只是一端的map满了,只需要调整start和finish迭代器。
2、如果两端都满了,就配置一块更大的map,把原map内容拷贝过来,释放原map,并重新设置map地址和大小,重新设置两个迭代器。

其他的pop_back,clear,erase,inset等操作都是大同小异的,感兴趣的自己再看看。

总结:deque是一个双端开口的连续线性空间,和vector比的话,它更灵活因为可以头部插入删除元素。
并且,这个线性是逻辑上的,实际上,deque会有一个map是连续的空间,中控器,存储的是双重指针,指针指向的是缓冲区位置。缓冲区默认512字节。map最少8个,最多缓冲区大小。会有一个start,end表示第一个和最后一个元素。注意缓冲区是从中间开始分配的,保证两边一致。
迭代器方面,有四个指针,分别是当前位置以及当前缓冲区的开始和结尾,以及是第几个缓冲区。++,–需要考虑是否需要跳跃缓冲区。
当map一辺满了只需要调整start,end就可以。两边都满就要重新配置map,设置迭代器。

可以发现,deque为了解决内存不足重新申请,拷贝移动。采用map+缓冲区。利用map来组合一段段的缓冲区,代价是更复杂的数据结构和迭代器设计。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值