【STL】deque

deque源码实现

G2.9版本的deque源码

deque对外呈现出的是一个双向数组,其示意图和代码如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • deque内部实际上是由一个个离散的内存段组成的,术语叫做buffer,这些buffer的头指针被保存在一个map(表)中,通过deque的迭代器的行为,就可以对外表现为一个连续的内存段(示意图中的map不是容器来的…不要搞混了,map表可以往左右两边扩充,同时map前后各留了一个node节点,以便扩充可用,map一开始没有像vector一样有capacity(),所以当发现当前容量不够时会立即释放当前内存,重新申请内存)
  • 可以看出deque内部包含两个迭代器start和finish,分别指向头尾,除此之外还有一个map指向保存指向buffer的指针的内存段,以及一个表示map长度的map_size。
  • 观察deque的迭代器我们可以看出,里面包含四个指针,其中cur,first,last是指示当前buffer中位置的指针,node是指示当前buffer在整个map中位置的指针。cur表示元素在当前buffer中的位置,first和last分别标记该buffer的头尾,方便iterator进行后续的边界判断
  • deque初始长度为40字节,因为deque中有2个iterator(包含cur,first,last,node),1个map_pointer,1个size_type(4字节)
  • G2.9允许用户自己定义每一个buffer的大小

G4.9版本的deque源码

在这里插入图片描述

deque的insert()

iterator insert(iterator position, const value_type& x){
    if(position.cur == start.cur){ //如果安插点是deque最前端,那么交给push_front()做插入
        push_front(x);
        return start;
    }
    else if(position.cur == finish.cur){ //如果安插点是deque最尾端,那么交给push_back()做插入
        push_back(x);
        iterator tmp = finish;
        --tmp;
        return tmp;
    }
    else{
        return insert_aux(position, x);
    }
}
 
template <class T, class Alloc, size_t BufSize>
typename deque<T, Alloc, BufSize>::iterator
deque<T, Alloc, BufSize>::insert_aux(iterator pos, const value_type& x){
    difference_type index = pos - start;    //安插点之前的元素个数
    value_type x_copy = x;
    if(index < size() / 2){                //如果安插点之前的元素个数较少
        push_front(front());               //在最前端加入与第一元素同值的元素
        ......
        copy(front2, pos1, front1);        //元素搬移
    }    
    else{                                   //安插点之后的元素个数较少
        push_back(back());                 //在尾端加入与最末元素同值的元素
        ......
        copy_backward(pos, back2, back1);  //元素搬移
    }
    *pos = x_copy;                         //在安插点设定新值
    return pos;
}
  • insert()巧妙之处在于先判断插入位置靠近头还是尾,然后将数据进行往前或者往后搬移腾出位置来塞插入的元素。

deque如何模拟连续空间

由于deque中定义了operator[],size()等操作,所以用户在使用deque的时候,感觉仿佛是在对一段连续空间进行操作:

reference operator[](size_type n)
{ return start[difference_type(n)]; }

reference front()
{ return *start; }

reference back()
{ 
	iterator tmp = finish;
	tmp--;
	return *tmp; 
}

size_type size()const
{ return finish-start; }

size_type empty()const
{ return finish == start; }

deque模拟连续空间有赖于deque iterator对于运算符的重载:

reference operator*()const
{ return *cur; }

pointer operator->()const
{ return &(operatro*()); }

difference_type operator-(const self& x) const
{
    return difference_type(buffer_size()) * (node - x.node - 1) + //首尾buffers之间的buffers数量
           (cur - first) +  //末尾buffer的元素量
           (x.last - x.cur);  //起始buffer的元素量
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意事项

deque的迭代器类型以及相关操作的时间复杂度
随机访问迭代器
随机访问每个元素 常量时间
末尾插入删除元素 常量时间
中间或开头删插元素 线性时间

deque的迭代器失效问题
插入元素

  • 头尾
    可能使所有元素的迭代器失效(buffer中一段连续空间满,需释放map内存,并重新分配map和buffer的内存时),也可能指向头或尾的元素的迭代器将失效,指向其他元素的迭代器,但指针、引用仍有效(buffer的原有空间并未发生改变)
  • 其他位置
    迭代器、指针、引用失效

删除元素

  • 头尾
    指向头或尾的元素的迭代器将失效,指向其他元素的迭代器、指针、引用仍然有效(buffer的原有空间并未发生改变)
  • 其他位置
    迭代器、指针、引用失效
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值