deque

STL容器——deque

vector是单向开口的连续线性空间,deque是一种双向开口的连续线性空间。所谓双向开口,意思是可以在头尾两端分别做元素的插入和删除操作。

dequevector的最大差异,一在于deque允许常数时间内对起头端进行元素的插入或移除操作,二是在于deque没有所谓容量(capacity)的概念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。换句话说,像vector那样“因旧空间不足而重新配置一块更大的空间,然后复制元素,再释放旧空间”这样的事情在deque是不会发生的。因此,deque没有必要提供所谓的空间保留功能。

虽然deque也提供random access iterator,但它的迭代器并不是普通指针。除非必要,我们应尽可能选择使用vector而非deque,对deque进行的排序操作,为了最高效率,可将deque先完整复制到一个vector身上,将vector排序后,再复制到deque

在这里插入图片描述

deque的中控器

deque由一段一段的定量连续空间构成,一旦有必要在deque的前端或尾端增加新空间,便配置一段定量连续空间,串接在整个deque的头端或尾端,deque的最大任务,便是在这些分段的定量连续空间上,维护其整体连续的假象,并提供随机存取的接口,避开了“重新配置,复制,释放”的轮回,代价则是复杂的迭代器架构

deque采用一块所谓的map(注意,不是STLmap容器)作为主控,这里所谓map是一小块连续空间,其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体SGI STL允许我们指定缓冲区大小,默认值0标识将使用512字节缓冲区。

template<class T, class Alloc = alloc, size_t BufSiz = 0>
class deque{
public:
    typedef T value_type;
    typedef value_type* pointer;
    ...
protected:
    //元素的指针的指针
    typedef pointer* map_pointer;

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

map其实就是一个T**,也就是说它是一个指针,所指之物又是一个指针,指向类型为T的一块空间。

在这里插入图片描述

deque的迭代器

deque是分段连续空间。维持其“整体连续”假象的任务,落在了迭代器operator++operator--两个运算子身上。

template<class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator{
  	typedef __deque_iterator<T, T&, T*, BufSize> iterator;
    typedef __deque_iterator<T,const T&,const T*,BufSiz> const_iterator;
    static size_t buffer_size() { return __deque_buf_size(BufSiz, sizeof(T)); }
    
    //如果n不为0,传回n,表示buffer_size由用户自行定义
    //如果n为0,表示buffer_size使用默认值,那么
    //如果sz(元素大小,sizeof(value_type))小于512,传回512/sz
    //如果sz不小于512,返回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));
    }
    
    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;	//指向管控中心
    
    //调用set_node跳到目的缓冲区
    void set_node(map_pointer new_node){
        node = new_node;
        first = *new_node;
        last = first + difference_type(buffer_size());
    }
    
    reference 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);	//就切换到下一个节点(缓冲区)
            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--;
        return *this;
    }
    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;
        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+(differnece_type n) const {}
    self& operator-=(difference_type n) {}
    
    self operator-(difference_type n) const {}
    
    reference operator[](difference_type n) const {}
    
    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的指针外,也维护startfinish,两个迭代器,分别指向第一缓冲区的第一个元素和最后缓冲区的最后一个元素(的下一个位置)。此为,它当然也必须记住目前的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;
	
    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)];
    }
    
    reference front() { return *start; }
    reference back(){
     	iterator tmp = finish;
        --tmp;
        return *tmp;
    }
    
    size_type size() const { return finish - start; }
	size_type max_size() const { return size_type(-1); }
    bool empty() const { return finish == start; }
};

在这里插入图片描述

deque的构造与内存管理

deque自行定义了两个专属的空间配置器。

protected:
	//专属空间配置器,每次配置一个元素大小
	typedef simple_alloc<value_type, Alloc> data_allocator;
	//专属空间配置器,每次配置一个指针大小
	typedef simple_alloc<pointer,Alloc> map_allocator;

并提供了一个constructor如下:

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

fill_initialize负责产生并安排好deque结构,并将元素的初值设置妥当

template<class T, class Alloc, size_t BufSize>
void deque<T,Alloc, BufSize>::fill_initialize(size_type n, const value_type& value)
{
	create_map_and_nodes(n);	//把deque的结构都产生并安排好
    map_pointer cur;
    __STL_TRY{
        for(cur = start.node; cur < finish.node; ++cur)
            uninitialized_fill(*cur,*cur + buffer_size(), value);
        uninitialized_fill(finish.first, finish.cur,value);
    }
    catch(...){
        ...
    }
}

其中create_map_and_nodes()负责产生并安排好deque的结构

template<class T, class Alloc, size_t BufSize>
void deque<T,Alloc, BufSize>::create_map_and_nodes(size_type num_elements)
{
    //需要节点数=(元素个数/每个缓冲区可容纳的元素个数) + 1
    //如果刚好郑楚,会多配一个节点
    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_size节点”map
    
    //令nstart和nfinish指向map所拥有的全部节点的最中央区段
    //保持再最中央,可使头尾两端的扩充能量一样大,每个节点可对应一个缓冲区
    map_pointer nstart = map + (map_size - num_nodes) / 2;
    map_pointer nfinish = nstart + num_nodes - 1;
    
    map_pointer cur;
    __STL_TYR{
        //为map内的每个节点配置缓冲区,所有缓冲区加起来就是deque的
        //可用空间
        for(cur = nstart; cur <= nfinish;++cur)
            *cur = allocate_node();		//配置一个缓冲区
    }
    catch(...){}
    
    start.set_node(nstart);
    finish.set_node(nfinish);
    start.cur = start.first;
    finish.cur = finish.first + num_elements % buffer_size();
}

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值