deque的迭代器
deque是分段连续空间,维持其"整体连续"的假象任务,落在了迭代器的operator++和operator--两个运算子身上。
对于operator:1、必须能够指出分段连续空间(即缓冲区)在哪里
2、必须能够判断自己是否已经处于其所在缓冲区的边缘,在跳跃时,必须掌握控制中心。
如下图:
template <class T,class Ref,class Ptr,size_t Bufsize> struct __deque_iterator{ //为继承 std::iterator typedef __deque_iterator<T,T&,T*,Bufsize> iterator; typedef __deque_iterator<T,const T&,const T*,Bufsize> const_iterator; static size_t buffer_size(){return __deque_buf_size(Bufsize,sizeof(T));} //未继承std::iterator,所以必须自行撰写五个必要的迭代器相应型别 typedef random_access_iterator_tag iterator_category; //1 typedef T value_type; //2 typedef Ptr pointer; //3 typedef Ref renference; //4 typedef size_t size_type; typedef ptrdiff_t difference_type; //5 typedef T** map_pointer; typedef __deque_iterator self; //保持与容器的联结 T* cur; //此迭代器所指之缓冲区中的现行(current)元素 T* first; //此迭代器所指之缓冲区中的头 T* last; //此迭代器所指之缓冲区中的尾(含备用空间) map_pointer node; //指向管控中心 ... 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)); } /* n!=0,返回n,表示buffer_size由用户自定义 n=0,表示buffer_size使用默认值,那么: sz<512,传回512/sz; sz>=512,传回1 */ };
例如:产生一个deque<int>,令缓冲区大小为32,于是每个缓冲区可以容纳32/sizeof(int)=8个元素,经过增删操作,deque中包含20个元素,deque情况如下图:
start和finish分别指向deque的第一个缓冲区和最后一个缓冲区,20/8=3,所以map拥有3个节点,且最后一个缓冲区还有插入元素的空间。
用于迭代器内对各种指针运算都进行重载操作,所以各种运算算法都比较麻烦,特别是对于在缓冲区边缘的元素操作都需要调用set_node操作,来跳一个缓冲区。代码如下:
void set_node(map_pointer new_node){
node=new_node;
first=*new_node;
last=first+difference_type(buffer_size());
}
重载运算符如下:
renference operator*() const {return *cur;}
pointer operator->() const {return &(operator*());}
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); //利用set_node方法切换到下一个缓冲区
cur=first;
}
return *this;
}
self operator++(int){
self temp=*this;
++*this; //调用operator++
return temp;
}
self& operator--(){
if(cur==first){ //如果达到缓冲区的头部
set_node(node-1); //利用set_node方法切换到上一个缓冲区
cur=first;
}
--cur;
return *this;
}
self operator--(int){
self temp=*this;
--*this; //调用operator--
return temp;
}
self& operator+=(difference_type n){ //实现随机存取、迭代器可以直接跳跃n个距离
difference_type offset=n+(cur-first);
if(offset>=0&&offset<difference_type(buffer_size())) //目标位置在统一缓冲区
cur+=n;
else{ //目标位置在统一缓冲区
difference_type node_offset=offset>0?
offset/difference_type(buffer_size()):-difference_type((-offset-1)/buffer_size())-1;
set_node(node+node_offset); //切换至正确的节点
cur=first+(offset-node_offset*difference_type(buffer_size()); //切换至正确的元素
}
return *this;
}
self operator+(difference_type n) const{
self temp=*this;
return temp+=n; //调用operator+=
}
self& operator-=(difference_type n){
return *this+=-n;
}
self operator-(difference_type n) const{
self temp=*this;
return temp-=n; //调用operator-=
}
//随机存取第n个元素
reference operator[](difference_type n)const {return *(*this+n);}
bool operator==(const self& x)const{return cur==x.cur;}
bool operator!=(const self& x)const{return !(*this==x);}
bool operator<(const self& x)const{
return (node==x.node)?(cur<x.cur):(node<x.node);
}
deque的数据结构
deque除了维护上文map的指针外,还要维护start,finish两个迭代器(上图2可见),分别指向第一个缓冲区的第一个元素和最后一个缓冲区的最后一个元素的下一个位置(可能还有备用空间),此外,它当然也必须记住目前的map大小,因为一旦map所提供的节点不足,就必须重新配置更大的一块map。
template <class T,class Alloc=alloc,size_t BufSiz=0>
class deque{
public:
typedef T value_type;
typedef value_type* pointer;
typedef size_t size_type;
public:
typedef __deque_iterator<T,T&,T*,BufSiz> iterator;
protected:
typedef pointer* map_pointer;//元素的指针的指针
protected:
iterator start; //表示第一个节点
iterator finish; //表示最后一个节点
map_pointer map; //指向map,map是块连续空间,其每个元素都是指针,指向一个节点
size_type map_size; //map内有多个指针
...
public:
iterator begin(){return start;}
iterator end(){return finish;}
reference operator[](size_type n){
return start[difference_type(n)]; //调用operator[]
}
reference front(){return *start;} //调用operator*
reference back(){
iterator temp=finish;
--temp; //调用operator--
return *temp; //调用operator*
}
size_type size() const{return finish-start;} //调用operator-
size_type max_size() const{return size_type(-1);}
bool empty() const{return finish==start;}
};