deque是一种双向开口的连续线性空间,vector是单向开口的连续线性空间。
deque与vector区别:1、deque是双向开口的连续节点,2、deque没有所谓容量概念。
deque是分段连续的空间,由一段一段的定量连续空间构成,
deque类源码:
template <class T>
class deque{
public:
typedef T value_type;
typedef value_type* pointer;
protected:
typedef pointer* map_pointer;
map_pointer map; //指向map,map是块连续空间,其内的每个元素都是一个指针(称为节点),指向一块缓冲区
size_type map_size; //map中可容纳的指针数
// 数据成员
protected:
iterator start;
iterator finish;
map_pointer map;
size_type map_size;
};
deque的迭代器,具体实现下图可以看出:
迭代器的几个关键行为:
当指针的加减等运算,遇到缓冲区边缘,就需要调用ser_node()跳一个缓冲区:
void set_node(map_pointer new_node){ //注意:没有对cur进行初始化,所以跳转一个缓冲区时不要忘了设置cur节点
node=new_node;
first=*new_node;
last=first+difference_type(buffer_size());
}
//各种运算符的重载
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 tmp;
}
//实现随机存取,迭代器直接跳跃n个距离
self&
operator+=(different_type n){
different_type offset=n+(cur-first);
if(offset>=0&&offset<different_type(buffer_size())){ //在同一缓冲区
cur+=n;
}else{ //不在同一缓冲区内
different_type node_different=offset>0?offset/buffer_size():-(-offset-1)/buffer_size()-1;
set_node(node_different);
cur=first+(offset-node_different*buffer_size());
}
return *this;
}
//加法操作
self
operator+(difference_type n) const{
self tmp=*this;
return tmp+=n;
}
deque的数据结构:
begin() end() operator[] front() back() size() empty() 略
push_back:
void push_back(const value_type& t){
if(finish.cur!=finish.last-1){ //最后缓冲区还有两个及以上元素空间备用,可直接插入
construct(finish.cur,t);
++finish.cur;
}
else //新增一块新的缓冲区
push_back_aux(t);
}
void push_back_aux(const value_type& t){
value_type t_copy=t;
reserve_map_at_back(); //若map的大小不够用,则需要
换一个更大的map空间(配置更大的、拷贝原来的、释放原来的)
*(finish.node+1)=allocate_node(); //配置一个新的节点,即新缓冲区
{
construct(finish.cur, t_copy);
finish.set_node(finish.node+1);
finish.cur=finish.first;
}
}
push_front同理,首先判断start.cur和start.first是否相等,即是否需要增加一块缓冲区,如果不需要,可直接插入,否则,新增一块缓冲区并配置节点,改变start的值。
pop_back: //pop_back、pop_front与push_back、push_front并无太大差异,不过就是删除或插入节点,需要重新分配或者释放缓冲区
void pop_back(){
if(finish.cur!=finish.first){ //无需释放缓冲区
--finish.cur;
destory(finish.cur);
}
else
pop_back_aux(); //需要释放缓冲区
}
void pop_back_aux(){
deallocate_node(finish.first); //释放最后一个缓冲区
finish.set_node(finish.node-1); //跳转缓冲区
finish.cur=finish.last-1;
destory(finish.cur); //将该元素析构
}
pop_front与pop_back无异,前面判断的是start.cur==start.last-1;
erase:删除某个特定位置的元素,时间复杂度为O(n),删除之后需要将后面元素前移,并释放最后一个元素。
iterator erase(iterator pos){ //返回删除元素后的
iterator next=pos;
++next;
difference_type index=pos-start; //判断该清除节点离头结点近还是离尾节点近,然后选择移动少的那部分
if(index<(size()-1)){
copy_backward(start, pos, next);
pop_front();
}
else{
copy(next, finish, pos);
pop_back();
}
return start+index; //此时next指针和pos指针失效,因此返回start+index,删除元素后元素的迭代器。
}
deque erase(iterator first, iterator last){......} //删除[first,last)间的元素。
insert: //时间复杂度O(n),需要前移或后移其余元素
iterator insert(iterator pos, const value_type& x){
if(pos.cur==first.cur){ //插入点是deque的最前端,交给push_front
push_front(x);
return first;
}
else if(pos.cur==finish.cur){ //插入点是deque的最后端,交给push_back
push_back(x);
iterator tmp=finish.cur; //返回的迭代器要指向插入的节点,而finish指向最后一个节点后面的节点,因此需要向前移一步
--tmp;
return tmp;
}
else{ //在deque中间位置插入
return insert_aux(pos, x);
}
}
deque insert_aux(iterator pos, const value_type& x){
difference_type index=pos-first; //计算插入节点与头结点的距离,选择较小部分进行前移或后移
value_type x_copy=x;
if(index<size()/2) {
push_front(front());
iterator front1=start;
++front1;
iterator front2=front1;
++front2;
pos=front+index;
iterator pos1=pos;
++pos1;
copy(front2, pos2, front1);
}
else{
push_back(back());
iterator back1=finish;
--back1;
iterator back2=back1;
--back2;
pos=start+index;
copy_backward(pos, back2, back1);
}
*pos=x_copy;
return pos;
}