STL源码学习系列九: 序列式容器( Deque)

12 篇文章 1 订阅
12 篇文章 15 订阅

序列式容器( Deque)


概述

deque是一种双向开口的分段连续线性空间,可以在头尾端进行元素的插入和删除。
这里写图片描述
deque与vector最大的差异就是:第一是deque允许于常数时间内对头端进行插入或删除元素;第二是deque是分段连续线性空间,随时可以增加一段新的空间;deque不像vector那样,vector当内存不够时,需重新分配/复制数据/释放原始空间;不过deque的迭代器设置比vector复杂,因为迭代器不能使用普通指针,因此尽量使用vector; 当对deque的元素进行排序时,为了提高效率,首先把deque数据复制到vector,利用vector的排序算法(利用STL的sort算法),排序之后再次复制回deque;


deque中控器

由于deque是分段连续线性空间的,为了用户方便操作,所以它对外的接口类似于连续空间。为了管理这些分段空间deque容器引入了一种中控器map,map是一块连续的空间,其中每个元素是指向缓冲区的指针,缓冲区才是deque存储数据的主体。SGI STL 允许指定缓冲区大小,默认值0表示将使用512bytes缓冲区。下面给出map的结构:

   //指向map,map是块连续空间,其内的元素都是一个指针(节点),指向一个缓冲区
   map_pointer map;
   //map内可以容纳多少指针
   size_type map_size;

结构图如下:
这里写图片描述


deque迭代器

deque是分段连续的线性空间,则普通指针不能作为deque的迭代器。迭代器设计时必须能够进行operator++或operator–操作,为了能够是用户随机访问容器,则必须对操作符进行重载。

deque迭代器的功能:

1. 必须知道缓冲区的位置
2. 能够判断是否处于其所在缓冲区的边界
3. 能够知道其所在缓冲区当前所指位置的元素

迭代器的数据结构如下:

   //与容器保持联结
   T* cur;   //此迭代器所指向缓冲区现行元素
   T* first;  //此迭代器所指向缓冲区的头
   T* last;  //尾
   map_pointer node; //控制中心

结构图如下:
这里写图片描述

迭代器源码:

#include "iterator.h"

namespace EasySTL
{
    template<class T,class Ref,class Ptr,size_t BufSize>
    struct _deque_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;
        typedef T value_type;
        typedef Ptr pointer;
        typedef Ref reference;
        typedef size_t size_type;
        typedef ptrdiff_t difference_type;
        typedef T** map_pointer;

        typedef _deque_iterator self;

        //与容器保持联结
        T* cur;   //此迭代器所指向缓冲区现行元素
        T* first;  //此迭代器所指向缓冲区的头
        T* last;  //尾
        map_pointer node; //控制中心

        static size_t _deque_buf_size(size_t n,size_t sz)
        {
            return n!=0?n:(sz<512?size_t(512/sz):size_t(1));
        }

        //将该迭代器指向新的缓冲区的第一个位置
        void set_node(map_pointer new_node)
        {
            node=new_node;
            first=*new_node;
            last=first + difference_type(buffer_size());
        }

        //以下各个重载运算子是 _deque_iterator<>成功的关键
        reference operator*() const {return *cur;}
        pointer operator->() const {return &(operator*());}
        difference_type operator-(const self& x) const
        {
            return defference_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;
        }

        self& operator--()
        {
            if(cur==first)
            {
                set_node(node-1);
                cur=last;
            }
            --cur;
        }

        self operator--(int)
        {
            self tmp=*this;
            --*this;
            return tmp;
        }

        //实现随机存取,迭代器可以直接跳跃n个距离
        self& operator+=(difference_type n)
        {
            difference_type offset = n + (cur-first);
            if(offset>0&&offset<(difference_type)(buffer_size()))
            {
                cur+=n;
                return *this;
            }
            if(offset>0) //不在同一缓冲区
            {
                difference_type left=n-(last-cur);
                difference_type node_diff=left/(difference_type)buffer_size();
                set_node(node+node_diff);
                cur=left%(difference_type)buffer_size();
                return *this;
            }
            if(offset<0)
            {
                difference_type left=n-(cur-first);
                difference_type node_diff=left/(difference_type)buffer_size();
                set_node(node-node_diff);
                cur=last-left%(difference_type)buffer_size();
                return *this;
            }
        }

        self operator+(difference_type n) const
        {
            self tmp=*this;
            return tmp+=n;
        }

        self& operator-=(difference_type n)
        {
            return *this+=-n;
        }

        self operator-(difference_type n) const
        {
            return *this+=-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 cur!=x.cur;}
        bool operator<(const self& x) const
        {
            return (node==x.node)?(cur<x.cur):(node<x.node);
        }

    };
}

deque容器数据结构

deque容器具有维护map和迭代器的功能,deque定义的两个迭代器分别是start和finish,分别指向第一个缓冲区的第一个元素和最后一个缓冲区的最后一个元素的下一个位置:

 template<class T,class Alloc=alloc,size_t BufSize=0>
 class deque
 {
       public:
            typedef _deque_iterator<T,T&,T*,BufSize> iterator;

        protected:
            //元素的指针的指针
            typedef pointer* map_pointer;

        protected:
            iterator start;
            iterator finish;
            //指向map,map是块连续空间,其内的元素都是一个指针(节点),指向一个缓冲区
            map_pointer map;
            //map内可以容纳多少指针
            size_type map_size; 
}

deque的示意图,书中设定的buffer是8,实际上buffer是通过待存储的元素的大小决定的,比如说如果存储int型,则大小就是512/4 = 128书中的一个图示,源码中的函数都可以通过该图示简单的计算:
这里写图片描述


deque构造函数和析构函数

  deque():start(),finish(),map_size(0),map(0)
  {
      create_map_and_nodes(0);
  }
  deque(int n,const value_type& value):start(),finish(),map(0),map_size(0)
  {
      fill_initialize(n,value);
  }
  ~deque(){}

  void fill_initialize(size_type n,const value_type& value)
  { //负责产生并安排好deque的结构,并将元素的初值设定好
        create_map_and_nodes(n); //把deque的结构都安排好
        map_pointer cur;
        //已经获得空间,为每个节点缓冲区设定初值
        for(cur=start.node;cur<finish.node;++cur)
        {
            uninitialized_fill(*cur,*cur+buffer_size(),value);
        }
        //最后一个节点的设定稍有不同(尾端可能有备用空间,不必设初值)
        uninitialized_fill(finish.first,finish.cur,value);
    }

    void creat_map_and_nodes(size_type num_elements)
    { //产生并安排好deque的结构
        size_type num_nodes=num_elements/buffer_size()+1; 
        //一个map要管理几个节点,最少8个,最多是“所需节点数+2”,前后各预留一个,扩充时用
        map_size=max(initial_map_size(),num_nodes+2);
        map=map_allocator::allocate(map_size);

        map_pointer nstart=map+(map_size-num_nodes)/2;
        map_pointer nfinish=nstart+num_nodes-1;
        map_pointer cur;

        for(cur=nstart;cur<=nfinish;cur++)
        {
            *cur=allocate_node();
        }
        start.set_node(nstart);
        finish.set_node(nfinish);
        start.cur=start.first;
        finish.cur=finish.first+num_elements%buffer_size();
    }

deque成员函数

#ifndef _DEQUE_H_
#define _DEQUE_H_

#include "dequeIterator.h"
#include "allocator.h"
#include "construct.h"
#include "algorithm.h"
#include "uninitialized.h"

enum {_min_map_num = 8};

namespace EasySTL 
{
    template<class T,class Alloc=alloc,size_t BufSize=0>
    class deque
    {
    public:
        typedef T value_type;
        typedef value_type* pointer;
        typedef value_type& reference;
        typedef size_t size_type;
        typedef ptrdiff_t difference_type;

    public:
        typedef _deque_iterator<T,T&,T*,BufSize> iterator;

    protected:
        //元素的指针的指针
        typedef pointer* map_pointer;
    protected:
        //配置一个元素大小,value
        typedef simple_alloc<value_type,Alloc> data_allocator;
        //配置一个指针大小,map
        typedef simple_alloc<pointer,Alloc> map_allocator;

        pointer allocate_node()
        {
            return data_allocator::allocate(buffer_size());
        }

        static size_t buffer_size() {return _deque_buf_size(BufSize,sizeof(T));}

        static size_t _deque_buf_size(size_t n,size_t sz)
        {
            return n!=0?n:(sz<512?size_t(512/sz):size_t(1));
        }

        int initial_map_size()
        {
            return _min_map_num;
        }

    void fill_initialize(size_type n, const value_type& value);
    void create_map_and_nodes(size_type num_elements);

/*      
        void push_back_aux(const value_type& t);
        void push_front_aux(const value_type& t);
        void reserve_map_at_back(size_type node_to_add = 1);
        void reserve_map_at_front(size_type node_to_add = 1);
        void reallocate_map(size_type node_to_add, bool add_at_front);
        void pop_back_aux(); //finish.cur == finish.first 释放该缓冲区
        void pop_front_aux();
*/
/*
        void fill_initialize(size_type n,const value_type& value)
        { //负责产生并安排好deque的结构,并将元素的初值设定好
            create_map_and_nodes(n); //把deque的结构都安排好
            map_pointer cur;
            //已经获得空间,为每个节点缓冲区设定初值
            for(cur=start.node;cur<finish.node;++cur)
            {
                uninitialized_fill(*cur,*cur+buffer_size(),value);
            }
            //最后一个节点的设定稍有不同(尾端可能有备用空间,不必设初值)
            uninitialized_fill(finish.first,finish.cur,value);
        }

        void creat_map_and_nodes(size_type num_elements)
        { //产生并安排好deque的结构
            size_type num_nodes=num_elements/buffer_size()+1; 
            //一个map要管理几个节点,最少8个,最多是“所需节点数+2”,前后各预留一个,扩充时用
            map_size=max(initial_map_size(),num_nodes+2);
            map=map_allocator::allocate(map_size);

            map_pointer nstart=map+(map_size-num_nodes)/2;
            map_pointer nfinish=nstart+num_nodes-1;
            map_pointer cur;

            for(cur=nstart;cur<=nfinish;cur++)
            {
                *cur=allocate_node();
            }
            start.set_node(nstart);
            finish.set_node(nfinish);
            start.cur=start.first;
            finish.cur=finish.first+num_elements%buffer_size();
        }
*/

    public:
        deque():start(),finish(),map_size(0),map(0)
        {
            create_map_and_nodes(0);
        }
        deque(int n,const value_type& value):start(),finish(),map(0),map_size(0)
        {
            fill_initialize(n,value);
        }
        ~deque(){}


        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_front(const value_type&t)
        {
            if(start.cur!=start.first)
            {
                construct(start.cur-1,t);
            }
            else
            {
                push_front_aux(t);
            }
        }

        void pop_back()
        {
            if(finish.cur!=finish.first)
            {
                --finish.cur;
                destroy(finish.cur); //将最后元素析构,左开右闭
            }
            else
            {
                //最后缓冲区没有任何元素
                pop_back_aux();  //这里将进行缓冲区的释放工作
            }
        }

        void pop_front()
        {
            if(start.cur!=start.last-1)
            {
                destroy(start.cur);
                ++start.cur;
            }
            else pop_front_aux();
        }

        void push_back_aux(const value_type& t) //只剩最后一个缓冲区的最后一个备用缓冲区
        { //先配置一块新的缓冲区,再设新元素内容,更改迭代器finish的状态
            value_type t_copy=t;
            reserve_map_at_back();  //若符合某种条件,则必须重换一个map
            *(finish.node+1)=allocate_node();  //配置一新缓冲区
            construct(finish.cur,t_copy);
            finish.set_node(finish.node+1);
            finish.cur=finish.first;
        }

        void push_front_aux(const value_type& t)
        {
            value_type t_copy=t;
            reserve_map_at_front();  
            *(start.node-1)=allocate_node();
            start.set_node(start.node-1);
            start.cur=start.last-1;
            construct(start.cur,t_copy);
        }

        void reserve_map_at_back(size_type nodes_to_add=1)
        {
            if(nodes_to_add+1>map_size-(finish.node-map)) //map尾端的节点备用空间不足
            {
                //换一个map(配置更大的,拷贝原来的,释放原来的)
                reallocate_map(nodes_to_add,false);
            }
        }

        void reserve_map_at_front(size_type nodes_to_add=1)
        {
            if(nodes_to_add>start.node-map)
            {
                reallocate_map(nodes_to_add,true);
            }
        }

        void reallocate_map(size_type nodes_to_add,bool add_at_front)
        {
            size_type old_num_nodes=finish.node-start.node+1;
            size_type new_num_nodes=old_num_nodes+nodes_to_add;

            map_pointer new_nstart;
            if(map_size>2*new_num_nodes)
            {
                //偏到一边去,把他移到正中间
                new_nstart=map+(map_size-new_num_nodes)/2+(add_at_front?nodes_to_add:0);
                if(new_nstart<start.node)
                {
                    copy(start.node,finish.node+1,new_nstart);
                }
                else
                {
                    copy_backward(start.node,finish.node+1,new_nstart+old_num_nodes);
                }
            }
            else
            {
                size_type new_map_size=map_size+max(map_size,nodes_to_add);
                //配置一块空间,准备给新map使用
                map_pointer new_map=map_allocator::allocate(new_map_size);
                new_nstart=new_map+(new_map_size-new_num_nodes)/2+(add_at_front?nodes_to_add:0);
                copy(start.node,finish.node+1,new_nstart);

                map_allocator::deallocate(map,map_size); //释放原map
                map=new_map;
                map_size=new_map_size;
            }

            start.set_node(new_nstart);
            finish.set_node(new_nstart+old_num_nodes-1);
        }

        void pop_back_aux()
        { //finish.cur==finish.first 释放该缓冲区
            deallocate_node(finish.first);  //释放最后一个缓冲区
            finish.set_node(finish.node-1);
            finish.cur=finish.last-1;
            destroy(finish.cur); //析构
        }

        void pop_front_aux()
        {
            destory(start.cur);
            deallocate_node(start.last);
            start.set_node(start.node+1);
            start.cur=start.first;
        }

       void clear()
        {
            for(map_pointer node=start.node+1;node<finish.node;++node)
            {
                destory(*node,*node+buffer_size());  //析构元素
                data_allocator::deallocate(*node,buffer_size()); //释放内存
            }

            if(start.node!=finish.node)  //至少有两个缓冲区
            {
                destroy(start.cur,start.last);
                destroy(finish.first,finish.cur);
                //保留头缓冲区
                data_allocator::deallocate(finish.first,buffer_size());
            }
            else
            {
                destroy(start.cur,finish.cur);
            }
            finish=start;
        }

   protected:
        iterator start;
        iterator finish;
        //指向map,map是块连续空间,其内的元素都是一个指针(节点),指向一个缓冲区
        map_pointer map;
        //map内可以容纳多少指针
        size_type map_size; 

   public:
        iterator begin() {return start;}
        iterator end() {return finish;}

        reference operator[](size_type n)
        { 
            //调用_deque_iterator<>::operator[]
            return *(start + n);
        }

        reference front() {return *start;}
        reference back() {return *(finish-1);}

        size_type size()  const {return finish-start;}
        size_type max_size() const {return size_type(-1);}

        bool empty() const {return finish==start;}

    };
}
#include "deque.impl.h"    //条件编译
#endif

End

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值