STL(五):deque和stack,queue

前言

deque是一种序列式容器,翻译为双端队列,deque实现了常数级别的头尾的插入和删除操作,但代价是deque具有比vector复杂的多的机制。

deque的设计

deque的类图与vector非常相似,数据结构都是存放在_Deque_base中,deque继承_Deque_base,然后定义一些内嵌类型和成员方法。
在这里插入图片描述
类图中展示了deque的数据成员主要包括一个指针数组和两个迭代器,这与deque的结构有关,deque维护一个中控器,就是指针数组_M_map,中控器中每个元素指向一个数组,数组中是deque的元素,每个数组大小是固定的,这被称为buffer,而_M_map_size为中控器的长度。中控器是可以扩容的,扩容的过程与vector扩容相同。_M_start和_M_finish则分别指向deque的头元素和尾元素,下图表示了deque的结构。
在这里插入图片描述
_M_start和_M_finish迭代器中有四个成员,cur指向当前元素,first指向这条连续空间的第一个元素,last指向这条连续空间的最后一个元素,node则指向这条连续空间在_M_map中对应的节点。
deque要求至少包含8条buffer,并且至少预留一个头尾节点供插入使用,当需要对头节点进行插入时,如果_M_start中的buffer不够使用,那么就重新申请一条buffer放入中控器中,并更新_M_start,删除操作大致是相同的思路,因此,deque通过这种复杂的结构,实现了常数级别的头尾节点删除和插入。
相关代码量较大,可以下载文章末尾的源码自行查看。

deque中间插入元素

尽管deque对头尾的操作是常数级别,但其复杂的结构使得deque在中间插入元素时十分困难,这里省去其他调用过程,直接展示deque中间插入元素时最后调用的函数中的一个重载版本,其他版本大致类似。

template <class _Tp, class _Alloc>
typename deque<_Tp,_Alloc>::iterator 
deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos)
{
  difference_type __index = __pos - _M_start;
  if (__index < size() / 2) {
    push_front(front());
    iterator __front1 = _M_start;
    ++__front1;
    iterator __front2 = __front1;
    ++__front2;
    __pos = _M_start + __index;
    iterator __pos1 = __pos;
    ++__pos1;
    copy(__front2, __pos1, __front1);
  }
  else {
    push_back(back());
    iterator __back1 = _M_finish;
    --__back1;
    iterator __back2 = __back1;
    --__back2;
    __pos = _M_start + __index;
    copy_backward(__pos, __back2, __back1);
  }
  *__pos = value_type();
  return __pos;
}

deque先判断插入的位置,如果在前半部,则将后面的元素全部移动,后半部也是类似的操作,因此尽量不要使用deque的insert或是erase来增删中间元素。

_Deque_iterator

deque的iterator同样较复杂,上图中的_M_start和_M_finish就是_Deque_iterator类型,_Deque_iterator是一种random_access_iterator,包含下面四个元素:

  • _M_cur;
  • _M_first;
  • _M_last;
  • _M_node;
    其相关含义与_M_start、_M_finish一致。_Deque_iterator由于在地址上是不连续的,为了营造一种连续的假象,迭代器在指向buffer的last元素时调用operator++,必须指向下一个buffer的first元素,因此迭代器重载了operator++,当前类似的operator–,operator+=等等都需要重载。除了加减运算符外,还重载了operator[],这也符合random_access_iterator的语义。
    最后来看看deque的iterator失效的情况,当我们在头部或尾部进行插入时,不会影响原本的内存结构,因此不会导致迭代器失效,在头尾删除时也仅导致被删除的迭代器失效,而在中间进行插入和删除时,将使得deque的全部迭代器失效,这是因为可能会触发map的扩容,map扩容将使得所有迭代器的node成员失效。

stack和queue

stack和queue都是deque的适配器,其实非常简单,deque是两端开口的容器,stack和queue就是分别封住了deque的尾部和头部,本质上与deque相同。

SGI STL源码

deque相关源码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值