Deque
deque容器(双端队列)
deque是一种双向开口的分段连续线性空间(对外号称连续,使用者无法感知它是分段的)。deque支持从头尾两端进行元素的插入和删除。deque没有容量的概念,因为它是动态地以分段连续空间组合而成的。随时可以增加一段新的空间并连接起来。
deque 的迭代器
deque的迭代器是一个class
- node指向控制中心map,当迭代器++或-- 时,可以跳转到另一个分段
- first last指向当前所在buffer的头和尾,标记缓冲区的边界,当迭代器在走到当前buffer边界,下一步需要走到其他buffer(通过node)
- cur 当前迭代器指向的元素
template<class T,class Ref,class Ptr,size_t BufSiz>
struct __deque_iterator
{typedef random_access_iterator_tag iterator_category; //1typedef T value_type; //2typedef Ptr pointer; //3typedef Ref reference; //4typedef size_t size_type; typedef ptrdiff_t difference_type; //5typedef T** map_pointer;typedef __deque_iterator self;T* cur;T* first;T* last;map_pointer node;...
};
deque源码
template<class T,class Alloc=alloc,size_t BufSiz=0>
class deque
{
public:typedef T value_type;typedef __deque_iterator<T,T&,T*,BufSiz> iterator;protected:typedef pointer* map_pointer; //T**iterator start;iterator finish;map_pointer map;size_type map_size;public:iterator begin(){return start;}iterator end(){return end;}size_type size(){return finish-start;}...
};
为了维护这种整体连续的假象,带价就是迭代器的类型会比较复杂。即采用map(类型为T**)作为主控。map实际上是一块大小连续的空间,其中每一个元素,我们称之为node,每个node都指向了另一端连续线性的空间(上图的buffer),buffer才是deque真正存储空间的地方。
其中buffer大小的确定:
/*
n不为0,传回n,buffersize由user确定
n为0,buffersize使用预设值,如果sz(sizeof(value_type))小于512,传回512/sz,否则就传回1
*/
inline size_t __deque_buf_size(size_t n,size_t sz)
{return n!=0?n:(sz<512?size_t(512/sz):size_t(1));
}
deque插入元素
deque::insert()插入函数首先判断传入迭代器的位置是处于容器前半部分还是后半部分,再插入进比较短的那一段。
deque::insert()
iterator inset(iterator position,const value_type& x)
{if(position.cur==start.cur){push_front(x);return start;}else if(position.cur==finish.cur){push_back(x);return finish}else{return insert_aux(position,x);}
}
若插入位置是容器首部,则直接push_front,位置是容器尾部,则直接push_back。其他情况则调用insert_aux方法:
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,back2); //元素搬移}*pos = x_copy;return pos;
}