STL序列容器之deque

1、基本概念

  deque是双向开口的序列空间,可在常数时间内在头尾两段插入和删除元素,相比vector要高效很多。同时,deque没有容量的概念,其内部是以分段的连续空间组合而成的。就我看来,deque是vector和list的折中状态,兼和了vector的快速访问和list的空间动态增长,能够适应更加特殊的需求。

2、设计思路

  deque在内部使用一小块连续空间的map作为控制器,其中的每个元素指向另外一块连续空间的缓冲区,实际的数据是存储到缓冲区中的。
  控制器map初始大小为8,用于存储缓冲区,当空间不够存储新的缓冲区时,就需要扩充map的空间,扩充方式与vector的扩充方式一致,以下是实现源码:

size_type _Newsize = 0 < this->_Mapsize ? this->_Mapsize : 1;
while (_Newsize - this->_Mapsize < _Count || _Newsize < _DEQUEMAPSIZ)
{   // scale _Newsize to 2^N >= _Mapsize + _Count
    if (max_size() / _DEQUESIZ - _Newsize < _Newsize)
        _Xlen();    // result too long
    _Newsize *= 2;
}

  这里_DEQUEMAPSIZ就是map的初始大小8,map大小以2倍速率进行增长。
  缓冲区大小随STL版本的不同也是不同的,目前SGI STL是512个字节,而vs使用的STL设置的是16个字节。下面是SGI版本的源码:

inline size_t __deque_buf_size(size_t __size) {
  return __size < 512 ? size_t(512 / __size) : size_t(1);
}

  通过代码我们可以知道缓冲区的大小是固定不变的,vs版本也是一样不可更改。《STL源码剖析》一书中该函数是多一个参数的,我不知道是否是版本变更导致的。按照目前的源码,我们是完全无法更改缓冲区的大小的,这点留待后续深入了解下。

3、迭代器

  deque提供的迭代器能够更vector的迭代器一样进行一次移动n(n>=1)步,因而也是随机迭代器。但由于deque是分段连续空间,就需要迭代器处理好缓冲区跳转的问题。迭代器使用cur、first、last、node四个指针,其中cur指向缓冲器的当前位置,first指向缓冲区的第一个节点,last指向缓冲区的最后一个节点的下一个位置,遵循STL前开后闭的标准。

4、数据结构

  deque除了维护控制器map及map的大小外,还有start和finish两个迭代器,其中start指向第一个缓冲区,finish指向最后一个缓冲区。初始化时,deque会根据map的大小和缓冲区的数量调整start和finish的位置,使缓冲区设置到map的中间位置,方便后续向两头增长。下面是设置源码:

_Tp** __nstart = _M_map + (_M_map_size - __num_nodes) / 2;
_Tp** __nfinish = __nstart + __num_nodes;

  基于前开后闭的原则,start和finish操作是不一样的。分为以下四种情况:
1. push_front:start指向的缓冲区的空间是向左增长,start.cur==start.first时缓冲区满,此时再调用push_front时创建新的缓冲区;
2. pop_front:start.cur==start.last时缓冲区空,但是当start.cur==start.last-1,即缓冲区只剩一个元素时,此时调用pop_front会先销毁元素然后回收当前的缓冲区;
3. push_back: finish指向的缓冲区的空间向右增长 finish.cur==finish.last时缓冲区满,当finish.cur==finish.last-1,即缓冲区剩余一个位置时,此时再调用push_back会创建新的缓冲区,同时插入元素;
4. pop_back:finish.cur==finish.first是缓冲区空,此时调用pop_back时先回收当前缓冲区然后销毁元素。
  这里需要注意的是,对于插入,后插是在还有一个空余位置就会马上创建新的缓冲区;对于删除,前删是在只剩一个元素时就会马上回收缓冲区。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值