Deque
deque容器(双端队列)
deque是一种双向开口的分段连续线性空间(对外号称连续,使用者无法感知它是分段的)。deque支持从头尾两端进行元素的插入和删除。deque没有容量的概念,因为它是动态地以分段连续空间组合而成的。随时可以增加一段新的空间并连接起来。
deque用vector存储buffer,当前vector容量满了之后,vector二倍扩容,将原始数据拷贝到新数据的中段,
使得map 可以向两端扩容
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;
}
deque如何模拟连续的空间:
reference operator[](size_type n){return start[difference_type(n)];
}reference front(){return *start;
}
reference back(){iterator tmp = finish;--temp;return *temp;
}size_type size()const{return finish-start;
}bool empty()const{return finish==start;
}
重要的操作符重载: -
- 重载 判断两个迭代器之间的距离:
两个迭代之间的buffer数量 + it1 到其尾部的长度 + it2 到其头部的长度
reference operator*()const{return *cur;
}pointer operator->()const{return &(operator*());
}//两根iterator之间的距离相当于 两根iterators之间的buffers的总长度+it1至其buffer尾部长度+it2至其buffer头部的长度
difference_type operator-(const self& x)const{return difference_type(buffer_size())*(node-x.node-1)+(cur-first)+(x.last-x.cur);
}
self& operator++(){++cur;if(cur==last){set_node(node+1); //跳到下一节点的起始节点cur = first;}return *this;
}self operator++(int){self tmp = *this;++*this;return temp;
}self& operator--(){--cur;if(cur==first){set_node(node-1); //跳到上一节点的尾节点cur = last;}return *this;
}self operator--(int){self tmp = *this;--*this;return temp;
}void set_node(map_pointer new_node){node = new_node;first = *node;last = first+difference_type(buffer_size());
}self& operator+=(difference_type n)
{difference_type offset = n+(cur-first);if(offset>=0&&offset<difference_type(buffer_size()))// 目标在同一buffer内cur +=n;else{// 目标不在同一buffer内difference_type node_offset = offset>0?offset/difference_type(buffer_size()):-difference_type((-offset-1)/buffer_size())-1;// 切换至正确的buffer内set_node(node+node_offset);// 切换至正确的元素cur = first+(offset-node_offset*difference_type(buffer_size()));}return *this;
}self operator+(difference_type n){self tmp = *this;return temp+=n;
}
queue和stack默认封装了 deque
调用deque种的函数
queue
template<class T, class Sequence=deque<T>>
class queue {
public:typedef typename Sequence::value_type value_type;typedef typename Sequence::size_type size_type;typedef typename Sequence::reference reference;typedef typename Sequence::const_reference const_reference;
protected:Sequence c; // 底层容器,默认是deque<T>
public:bool empty() const { return c.empty(); }size_type size() const { return c.size(); }reference front() { return c.front(); }const_reference front() const { return c.front(); }reference back() { return c.back(); }const_reference back() const { return c.back(); }void push(const value_type &x) { c.push_back(x); }void pop() { c.pop_front(); }// ...
};
stack
template<class T, class Sequence=deque<T> >
class stack {
public:typedef typename Sequence::value_type value_type;typedef typename Sequence::size_type size_type;typedef typename Sequence::reference reference;typedef typename Sequence::const_reference const_reference;
protected:Sequence c;// 底层容器,默认是deque<T>
public:bool empty() const { return c.empty(); }size_type size() const { return c.size(); }reference top() { return c.back(); }const_reference top() const { return c.back(); }void push(const value_type &x) { c.push_back(x); }void pop() { c.pop_back(); }// ...
};
也可以指定其他容器,例如list、vector作为stack和queue的底层容器,因为它们内部也实现了对应所需要的方法。
queue<int, list<int>> q1;
for (long i = 0; i < 10; ++i) {q1.push(rand());
}stack<int, list<int>> s1;
for (long i = 0; i < 10; ++i) {s1.push(rand());
}stack<int, vector<int>> s2;
for (long i = 0; i < 10; ++i) {s2.push(rand());
}
stack 和 queue 都不允许遍历,也不提供迭代器
stack 和queue实际调用的是容器的函数,如果容器没有实现stack和queue的功能,比如map、set没有实现stack种的功能,不可以选择set或map作为stack queue的底层结构