从头到尾实现deque

来源:互联网 发布:win10视频桌面软件 编辑:程序博客网 时间:2024/04/30 15:07
关于deque内部数据结构的说明:
deque是能够同时在收尾进行插入和删除的数据结构。其表现形式看起来和vector差不多,但是在处理队头插入时,其表现的时间复杂度要远远地优越于vector。这个得益于deque的内部数据结构地实现。deque使用分段的连续空间组成。为了管理这个分段的连续空间,所以必须要有一个中控器来记录各个分段空间的首地址,然后需要一个长度来记录该中控器的大小。为了表现和vector相似,所以需要包含2个迭代器分别用来指向首尾元素。关于迭代器的内存元素:首先要有一个指针指向我们待表示的数据。然后就是该数据在那一个缓冲区上,为了在外面上表现为连续的空间,我们必须要记录该缓冲区的首尾地址,这样重载++的时候,能够方便的找到下一块地址。


其结构示意图如下:


其代码实现如下:

//deque的特性:(这段话中别人那copy过来的,因为感觉写的还不错)//   对于任何一个迭代器i//     i.node是map array中的某元素的地址. i.node的内容是一个指向某个结点的头的指针//     i.first == *(i.node)//     i.last  == i.first + node_size//     i.cur是一个指向[i.first, i.last)之间的指针//       注意: 这意味着i.cur永远是一个可以解引用的指针,//            即使其是一个指向结尾后元素的迭代器////   起点和终点总是非奇异(nonsingular)的迭代器.//     注意: 这意味着空deque一定有一个node, 而一个具有N个元素的deque//          (N是Buffer Size)一定有有两个nodes////   对于除了start.node和finish.node之外的每一个node, 每一个node中的元素//   都是一个初始化过的对象. 如果start.node == finish.node,//   那么[start.cur, finish.cur)都是未初始化的空间.//   否则, [start.cur, start.last)和[finish.first, finish.cur)都是初始化的对象,//   而[start.first, start.cur)和[finish.cur, finish.last)是未初始化的空间////   [map, map + map_size)是一个合法的非空区间//   [start.node, finish.node]是内含在[map, map + map_size)区间的合法区间//   一个在[map, map + map_size)区间内的指针指向一个分配过的node,//   当且仅当此指针在[start.node, finish.node]区间内#ifndef ITERATOR_DEQUE_H_INCLUDED#define ITERATOR_DEQUE_H_INCLUDED#include"my_iterator_base.h"namespace juine{     //用来决定缓存区的大小    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));    }    template<class T,size_t buf_size=0>    class Iterator_deque    {    public:        typedef T value_type;        typedef value_type* pointer;        typedef value_type& reference;        typedef ptrdiff_t difference_type;        typedef random_access_iterator_tag iterator_category;        typedef T** map_pointer;        pointer data;  //所要表示节点的位置        pointer first;  //所在分区的起始位置        pointer last;   //所在分区的末尾位置        map_pointer node;  //所在分区    public:        size_t buff_size() {  return __deque_buf_size(buf_size,64); }        //设定节点的位置        void set_node(map_pointer new_node)        {            node=new_node;            first=0;            last=0;            if(new_node!=0)            {                first=*new_node;                last=*new_node+difference_type(buff_size()); //表明又是左闭右开区间            }        }        //construct        Iterator_deque(pointer _data=0,map_pointer _node=0):data(_data){    set_node(_node);  }        Iterator_deque(const Iterator_deque& iter):data(iter.data),first(iter.first),last(iter.last),node(iter.node){}        Iterator_deque& operator=(const Iterator_deque& iter)        {            data=iter.data;            first=iter.first;            last=iter.last;            node=iter.node;            return *this;        }        //重载解引用,==,!=        reference operator*() { return *data;}        pointer operator->()  { return &(operator*());}        bool operator==(Iterator_deque iter){ return data==iter.data;}        bool operator!=(Iterator_deque iter){ return data!=iter.data; }        bool operator<=(Iterator_deque iter)        {            if(node==iter.node)                return data<=iter.data;            return node<=iter.node;        }        //随机迭代器必须重载++,--        Iterator_deque operator++()        {            data++;            if(data==last)            {                set_node(node+1);                data=first;            }            return *this;        }        Iterator_deque operator++(int)   //后置式的标准写法        {            Iterator_deque iter=*this;            ++*this;            return iter;        }        Iterator_deque operator--()        {            if(data==first)            {                set_node(node-1);                data=last;   //左闭右开            }            data--;            return *this;        }        Iterator_deque operator--(int)        {            Iterator_deque iter=*this;            --*this;            return iter;        }////////////////////////////////////////////////////////////////////////////////// 将迭代器向前移动n个元素, n可以为负//////////////////////////////////////////////////////////////////////////////////                     operator+=(difference_type n)//                                   ↓//                      offset = n + (cur - first)//                                   |//                                   |---------- offset > 0 ? &&//                                   |           移动后是否超出当前缓冲区?//               ----------------------------//           No  |                          |  Yes//               |                          |//               ↓                          |---------- offset > 0?//           cur += n;                      |//                              ----------------------------//                          Yes |                          | No//                              |                          |//                              ↓                          |//                   计算要向后移动多少个缓冲区                |//                   node_offset =                         |//                   offset / difference_type              |//                   (buffer_size());                      ↓//                              |           计算要向前移动多少个缓冲区//                              |           node_offset = -difference_type//                              |           ((-offset - 1) / buffer_size()) - 1;//                              |                          |//                              ----------------------------//                                           |//                                           |//                                           ↓//                                       调整缓冲区//                              set_node(node + node_offset);//                                    计算并调整cur指针////////////////////////////////////////////////////////////////////////////////    // 以下实现随机存取。迭代器可以直接跳跃n个距离        Iterator_deque operator+=(difference_type n)        {            difference_type offset=n+(data-first);            if(offset>=0&&offset<difference_type(buff_size()))               //目标位置在同一个缓冲区内                data+=n;            else            {                //目标位置不在同一个缓冲区中                difference_type node_offset=                offset>0?offset/difference_type(buff_size()):-difference_type((-offset-1)/buff_size())-1;                //切换所在缓冲区                set_node(node+node_offset);                //切换所在目录                data=first+(offset-node_offset*difference_type(buff_size()));            }            return *this;        }        Iterator_deque operator+(size_t n)        {            Iterator_deque iter=*this;            return iter+=n;        }        /*        自己写的,发现效率还是比STL的低,而且STL中是将其+=,-=一起处理的        Iterator_deque operator-=(size_t n)        {            if(size_t(data-first)>=n)                data-=n;            else            {                //表示已经越界了该缓存区。                set_node(node-1);                n-=data-first;                data=last;                while(n>buff_size())                {                    set_node(node-1);                    n-=buff_size();                    data=last;                }                data-=n;            }            return *this;        }*/        Iterator_deque operator-=(size_t n)  {  return *this+=-n;}        Iterator_deque operator-(size_t n)        {            Iterator_deque iter=*this;            iter-=n;            return iter;        }        difference_type operator-(Iterator_deque iter)        {            difference_type offet=(node==iter.node)?data-iter.data:((data-first)+(iter.last-iter.data));            if(node-iter.node>1)                offet+=(node-iter.node-1)*buff_size();            return offet;        }    };}#endif // ITERATOR_DEQUE_H_INCLUDED

容器deque代码如下:

#ifndef MY_DEQUE_H_INCLUDED#define MY_DEQUE_H_INCLUDED#include"iterator_deque.h"#include<algorithm>#include<cstdlib>#include"simple_allocator.h"using std::cout;using std::endl;namespace juine{    template<class T,class Alloc=my_alloc,size_t buf_size=0>    class my_deque    {    public:        typedef T value_type;        typedef T* pointer;        typedef T& reference;        typedef size_t size_type;        typedef T** map_pointer;        typedef simple_allocator<T,Alloc>  data_container;        typedef simple_allocator<pointer,Alloc>  map_container;        typedef Iterator_deque<T,buf_size> iterator;    protected:        size_t map_size;    //申请map_node节点个数,再根据_map能获得map_node的尾节点        map_pointer _map;   //_map是申请的map_node节点的首地址        iterator start;        iterator finish;        size_t buff_size() {  return __deque_buf_size(buf_size,64); }        size_type initial_map_size() {    return 8 ;}        //构造函数时,将deque的结构安排好,初始化deque数据结构        void set_null(map_pointer first,map_pointer last)        {            //map节点是用来保存缓冲区地起始地址,            //但是占为使用的map节点应该保存NULL            map_pointer cur;            for(cur=first;cur<last;cur++)                *cur=NULL;        }        void create_map_and_nodes(size_t n)        {            cout<<"buff_size:"<<buff_size()<<endl;            size_type num_nodes=n/buff_size()+1;//当整除时也是要加1的            //map中控器的大小            //map_size=std::max(initial_map_size(),num_nodes+2);            //为了测试,map_size特殊化            map_size=num_nodes;            _map=map_container::alloc(map_size);            //以下是令nstart和nfinish指向map所拥有之全部节点的最中央区段            //保持在最中央,可使头尾两端扩充的能量一样大,每一节点可对应一个缓冲区            //(出现这种情况是因为,我们申请的节点数,是大于初始化时所需要的节点数,            //因此,需要将节点移动中间,使首尾平衡)            map_pointer nstart=_map+(map_size-num_nodes)/2;            map_pointer nfinish=nstart+num_nodes-1;            //申请缓冲区空间,申请节点为刚才所找到的平衡位置            map_pointer cur;            //申请到的node,暂时不指向缓冲区的应该将其值为NULL            set_null(_map,nstart);            set_null(nfinish,_map+map_size);            for(cur=nstart;cur<=nfinish;cur++)                *cur=data_container::alloc(buff_size());            //接下来是配置迭代器start,finish            start.set_node(nstart);            finish.set_node(nfinish);            start.data=*nstart;            finish.data=*nfinish+n%buff_size();        }        void fill_uninitialized()        {            //默认设定20个指针            _map=map_container::alloc(20);            map_size=20;        }        void fill_uninitialized(size_t n,value_type value)        {            //构造deque时,首先是产生deque的结构并安排组织好            create_map_and_nodes(n);            /*            以下注释部分自己写的,考虑不充分:自己强制规定map的大小,            当所需数据刚好为buf_size时,处理地方式也与STL不一样            _map=map_container::alloc(20);            map_size=20;            map_pointer temp=_map;            int remainder=n%buf_size;            int num=(remainder==0?n/bufsize:(n/buf_size+1));            while(num)            {                pointer p=data_container::alloc(buf_size);                if(num==1)                    uninitialized_fill_n(p,remainder==0?buf_size:remainder,value);  //最后一组只能填充remainder个元素                else                    uninitialized_fill_n(p,buf_size,value);                num--;                *temp=p; //将容器整个结构连接起来                temp++;            }            //对迭代器first,last进行初始化            iterator temp(*_map,*_map,*_map+buf_size-1,_map);            first=temp;            if(remainder!=0)            {                iterator temp1(*(_map+n/buf_size)+remainder-1,*(_map+n/buf_size),*(_map+n/buf_size)+remainder-1,_map+n/buf_size );                last=temp1;            }            else            {                iterator temp1(*(_map+n/buf_size-1)+buf_size-1,*(_map+n/buf_size),*(_map+n/buf_size-1)+buf_size-1,_map+n/buf_size-1 );                last=temp1;            }*/            //开始对申请到的节点进行初始化            map_pointer cur;            for(cur=start.node;cur<finish.node;cur++)                uninitialized_fill_n(*cur,buff_size(),value);            uninitialized_fill_n(finish.first,n%buff_size(),value);        }        template<class InputIterator>        void fill_uninitialized(InputIterator first,InputIterator last)        {            size_type num=last-first;            create_map_and_nodes(num);            //deque结构体已构造好,然后需要赋值            iterator iter=start;            while(first!=last)            {                construct(iter.data,*first);                iter++;                first++;            }        }        //释放内存        void dealloc()        {            cout<<"deque容器已释放"<<endl;            //先遍历map释放所有缓冲区            size_t i;            for(i=0;i<map_size;i++)                if(*(_map+i))   //当节点值为空时,表示其所指向缓冲区为空,不需要释放                {                    map_pointer temp=_map+i;                    destroy(*temp,*temp+buff_size());                    data_container::dealloc(*(_map+i));                }            //删除_map            map_container::dealloc(_map);        }    public:        //construct        my_deque(){    fill_uninitialized();}        my_deque(size_t n,value_type value) { fill_uninitialized(n,value);}        template<class InputIterator>        my_deque(InputIterator first,InputIterator last){ fill_uninitialized(first,last);}        ~my_deque(){ dealloc() ;}        iterator begin(){   return start; }        iterator end(){     return finish; }        reference operator[](size_type n)        {            iterator iter=start+n;            return *iter;        }        reference at(size_type n)        {            iterator iter=start+n;            if(finish<=iter)            {                cout<<"out of memory"<<endl;                exit(1);            }            return iter;        }        reference front(){  return *start; }        reference back(){   return *(finish-1); }        size_type size() {  return finish-start; }        bool empty(){   return start==finish; }        void push_front(value_type value){  insert(start,value); }        void push_back(value_type value){   insert(finish,value);}        //插入函数(考虑缓冲区大小够不,Map大小够不,还有效率-左移还是右移)        void insert(iterator position,value_type value)        {            if(position-start<=finish-position)  //表示需要左移动            {                iterator temp,new_start;                temp=new_start=insert_aux_left(1,position);                iterator temp1=start;                //这个地方赋值,利用了迭代器重载函数++,使其能够自动在片段连续空间上移动                while(temp1!=position)  //移动元素                    *temp++=*temp1++;                *temp=value;  //最后插入元素                start=new_start;   //插入之后,迭代器要更新,Temp保存的就是最新的位子            }            else            {                iterator temp,new_finish;                temp=new_finish=insert_aux_right(1,position);                iterator temp1=finish;                //这个地方赋值,利用了迭代器重载函数++,使其能够自动在片段连续空间上移动                while(temp1!=position)  //移动元素                    *--temp=*--temp1;                *position=value;  //最后插入元素                finish=new_finish;   //插入之后,迭代器要更新,Temp保            }        }        template<class InputIterator>        void insert(iterator position,InputIterator first,InputIterator last)        {            int n=last-first;            if(position-start<=finish-position)  //表示需要左移动            {                iterator temp,new_start;                temp=new_start=insert_aux_left(n,position);                iterator temp1=start;                //这个地方赋值,利用了迭代器重载函数++,使其能够自动在片段连续空间上移动                while(temp1!=position)  //移动元素                    *temp++=*temp1++;                while(temp!=position)                    *temp++=*first++;  //最后插入元素                start=new_start;            }            else            {                iterator temp,new_finish;                temp=new_finish=insert_aux_right(n,position);                iterator temp1=finish;                //这个地方赋值,利用了迭代器重载函数++,使其能够自动在片段连续空间上移动                while(temp1!=position)  //移动元素                    *--temp=*--temp1;                while(first!=last)                    *position++=*first++;  //最后插入元素                finish=new_finish;            }        }        //该函数功能:如容量不够,则扩充容量然后更新该deque结构        //该函数返回值,是表示在插入后,start迭代器所在正确位置        iterator insert_aux_left(size_t number,iterator& position)    //number表示插入的数据,而且该数据是左移的。        {            iterator result;            if(start.data-number<=start.first-1)  //表示前端缓冲区已满,因此要增加缓冲区            {                //要增加的缓冲区                int left_need_size=number-(start.data-start.first);                int need_map_nodes=left_need_size/buff_size()+1;                if(start.node-_map<need_map_nodes)  //表示中控器前端node节点不够了                {                    //虽然前面的不够,但是整个_map空余空间够,可以通过移动_map节点来实现                    //不用重新分配新的节点。                    if(size_t(finish.node-start.node+1+need_map_nodes)<=map_size)                    {                        cout<<"移动map达到要求"<<endl;                       //offset为map移动偏移量                        int offset=need_map_nodes-(start.node-_map);                        map_pointer temp=finish.node;                        while(temp>=start.node)                        {                            *(temp+offset)=*temp;                            temp--;                        }                        //前面_map移动后,finish中所存的Node,已经不是最后一个节点所在位置                        //故要移动,更新finish                        finish.node=finish.node+offset;                        //map前端node节点已够用,现在是要申请缓冲区内存                        map_pointer malloc_node=_map;                        while(malloc_node<(start.node+offset))                        {                            *malloc_node=data_container::alloc(buff_size());                            malloc_node++;                        }                        result.set_node(_map);                        result.data= *_map+buff_size()-left_need_size%buff_size();                    }                    else //map节点不够,需要重新分配其map_nodea                    {                        //map大小,简单以2倍来扩充                        map_pointer new_malloc_map=map_container::alloc(map_size*2);                        map_pointer item=new_malloc_map+map_size/2;                        map_pointer old_node=start.node;                        set_null(new_malloc_map,item);                        set_null(new_malloc_map+map_size,new_malloc_map+map_size*2);                        //将旧的map复制过来                        while(old_node<=finish.node)                            *item++=*old_node++;                        //因为map重新申请了,所以position也应该换到新map对应的位置上                        position.node=new_malloc_map+map_size/2+(position.node-start.node);                        //删除旧的map,释放内存                        map_container::dealloc(_map);                        start.node=new_malloc_map+map_size/2;                        finish.node=item-1;                        _map=new_malloc_map;                        map_size*=2;                         //需要申请内存                        map_pointer new_node=start.node-1;                        while(new_node>=start.node-need_map_nodes)                        {                            *new_node=data_container::alloc(buff_size());                            new_node--;                        }                        result.set_node(start.node-need_map_nodes);                        result.data= *result.node+buff_size()-left_need_size%buff_size();                    }                }                else //缓冲区不够,但是map前端所需node是够的                {                    //需要申请内存                    map_pointer new_node=start.node-1;                    while(new_node>=start.node-need_map_nodes)                    {                        *new_node=data_container::alloc(buff_size());                        new_node--;                    }                    result.set_node(start.node-need_map_nodes);                    result.data= *result.node+buff_size()-left_need_size%buff_size();                }            }            else //缓冲区是够的            {                result.data=start.data-number;                result.set_node(start.node);            }            return result;        }        iterator insert_aux_right(size_t number,iterator& position)    //number表示插入的数据,而且该数据是右移的。        {            iterator result;            if(finish.data+number>=finish.last)  //表示前端缓冲区已满,因此要增加缓冲区            {                //要增加的缓冲区                int left_need_size=number-(finish.last-finish.data-1);                int need_map_nodes=left_need_size/buff_size()+1;                if(_map+map_size-finish.node<need_map_nodes)   //表示中控器后端node节点不够了                {                    //虽然前面的不够,但是整个_map空余空间够,可以通过移动_map节点来实现                    //不用重新分配新的节点。                    if(size_t(finish.node-start.node+1+need_map_nodes)<=map_size)                    {                        cout<<"移动map达到要求"<<endl;                        //offset为map移动偏移量                        int offset=need_map_nodes-(_map-finish.node);                        map_pointer temp=start.node;                        while(temp<=finish.node)                        {                            *(temp-offset)=*temp;                            temp++;                        }                        //前面_map移动后,finish中所存的Node,已经不是最后一个节点所在位置                        //故要移动,更新finish                        start.node=start.node-offset;                        //map前端node节点已够用,现在是要申请缓冲区内存                        map_pointer malloc_node=_map+map_size;                        while(malloc_node>(finish.node-offset))                        {                            *malloc_node=data_container::alloc(buff_size());                            malloc_node--;                        }                        result.set_node(_map+map_size);                        result.data= *(_map+map_size)+left_need_size%buff_size();                    }                    else //map节点不够,需要重新分配其map_nodea                    {                        //map大小,简单以2倍来扩充                        map_pointer new_malloc_map=map_container::alloc(map_size*2);                        map_pointer item=new_malloc_map+map_size/2;                        map_pointer old_node=start.node;                        set_null(new_malloc_map,item);                        set_null(new_malloc_map+map_size,new_malloc_map+map_size*2);                        //将旧的map复制过来                        while(old_node<=finish.node)                            *item++=*old_node++;                        //因为map重新申请了,所以position也应该换到新map对应的位置上                        position.node=new_malloc_map+map_size/2+(position.node-start.node);                        //删除旧的map,释放内存                        map_container::dealloc(_map);                        start.node=new_malloc_map+map_size/2;                        finish.node=item-1;                        _map=new_malloc_map;                        map_size*=2;                         //需要申请内存                        map_pointer new_node=finish.node+1;                        while(new_node<=finish.node+need_map_nodes)                        {                            *new_node=data_container::alloc(buff_size());                            new_node++;                        }                        result.set_node(finish.node+need_map_nodes);                        result.data= *result.node+left_need_size%buff_size();                    }                }                else //缓冲区不够,但是map前端所需node是够的                {                    //需要申请内存                    map_pointer new_node=finish.node+1;                    while(new_node<=finish.node+need_map_nodes)                    {                        *new_node=data_container::alloc(buff_size());                        new_node++;                    }                    result.set_node(finish.node+need_map_nodes);                    result.data= *result.node+left_need_size%buff_size();                }            }            else //缓冲区是够的            {                result.data=finish.data+number;                result.set_node(finish.node);            }            return result;        }        //删除元素(为了简单,只写一种)        void erase(iterator position)        {            iterator temp;            if(position-start<=finish-position)  //左边的元素右移动            {                temp=position-1;                while(start<=temp)                {                    *(temp+1)=*temp;                    temp--;                }                start++;                if((start-1).node!=start.node)                    *(start-1).node=NULL;            }            else            {                temp=position+1;                while(temp!=finish)                {                    *(temp-1)=*temp;                    temp++;                }                finish--;                if((finish+1).node!=finish.node)                    *(finish+1).node=NULL;            }        }        void pop_back(){ erase(finish-1);}        void pop_front(){ erase(start);   }    };}#endif // MY_DEQUE_H_INCLUDED
测试代码如下:

#include<iostream>#include<cstdlib>#include<vector>#include"my_deque.h"using namespace std;using namespace juine;int main(){    int a[9]={1,2,3,4,5,6,7,8,9};    my_deque<int> tt(a,a+9);    tt.front()+=tt.back();    tt.back()+=tt.front();    my_deque<int>::iterator iter=tt.begin()+2;    tt.insert(iter,a,a+9);    tt.insert(tt.begin(),11);    tt.push_front(12);    tt.push_back(25);    tt.erase(tt.begin()+4);    tt.pop_front();    for(iter=tt.begin();iter!=tt.end();iter++)        cout<<*iter<<endl;    cout<<"size:"<<tt.size()<<endl;    return 0;}

测试结果为:


已基本达到要求,下一章实现序列容器。


1 0