【STL源码剖析】第四章 序列式容器 之 deque底层实现

deque

deque概述

vector是单向开口的连续线性空间,deque则是一种双向开口的连续线性空间。所谓双向开口,意思是可以在头尾两端分别做元素的插入和删除操所。vector当然也可以在头尾端进行操作(从技术观点),但是其从头部操作效率奇差,无法被接受。

deque和vector的最大差异,一在于deque允许常数时间内对起头端进行元素的插入或移除操作,二在于deque没有所谓的容量概念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。

虽然deque也提供了Ramdon Access Iterator,但它的迭代器并不是普通指针,其复杂度和vector不可以道里计,这影响了各个运算层面。因此,除非必要,应尽可能选用vector而非deque。对deque进行的排序操作,为了最高效率,可讲deque先完整复制到一个vector上,然后vector排序后,再复制到deque。

deque的中控器

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

deque采用一块所谓的map(不是STL的map容器)作为主控。这里所谓map是一小块连续空间,其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体。

  
  template<class T, class Alloc = alloc, size_t BufSiz = 0>  
  class deque{  
  public :  
      typedef T value_type ;  
      typedef value_type* pointer ;  
      ...  
  protected :  
      //元素的指针的指针(pointer of pointer of T)  
      typedef pointer* map_pointer ; //其实就是T**  
    
  protected :  
      map_pointer map ; //指向map,map是块连续空间,其内的每个元素  
                        //都是一个指针(称为节点),指向一块缓冲区  
      size_type map_size ;//map内可容纳多少指针  
      ...  
  };  

deque的迭代器

deque是分段连续空间。维持”整体连续“假象的任务,落在迭代器的operator++和operator—两个运算子上。deque的迭代器首先必须能指出分段连续空间在哪里,其次它必须能够判断自己是否以及处于其所在缓冲区的边缘,如果是,一旦前进或后退时就必须跳跃至下一个或上一个缓冲区。为了能够正确跳跃,deque必须随时掌控管控中心(map)。下面这个实现符合需求:

  
  template<class T, class Ref, class Ptr, size_t BufSiz>  
  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 ;  
      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 *cut ; //此迭代器所指之缓冲区中的现行(current)元素  
      T *first ; //此迭代器所指之缓冲区的头  
      T *last ;   //此迭代器所指之缓冲区的尾(含备用空间)  
      map_pointer node ; //指向管控中心  
      ...  
  };  

deque的数据结构

deque除了维护一个先前说过的指向map的指针外,也维护start,finish两个迭代器,分别指向第一缓冲区的第一个元素和最后缓冲区的最后一个元素(的下一个位置)。此外,它当然也必须记住目前的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 :  
      //元素的指针的指针(pointer of pointer of T)  
      typedef pointer*    map_pointer ;  
  protected:  
      iterator    start ; //表现第一节点  
      iterator    finish ; //表现最后一个节点  
      map_pointer map ; //指向map,map是块连续空间,其每个元素都是个指针,指向一个节点(缓冲区)  
      size_type   map_size ; //map内有多少指针  
      ...  
  } ;  

deque的构造与内存管理

  #include<iostream>
  #include<deque>
  #include<algorithm>
  using namespace std;
  
  int main(){
      deque<int,alloc,8> ideq(20, 9);
      cout << "size=" << ideq.size() << endl;
  
      for (int i = 0; i < ideq.size(); ++i)
          ideq[i] = i;
  
      for (int i = 0; i < ideq.size(); ++i)
          cout << ideq[i] << ' ';
      cout << endl;
  
      for (int i = 0; i < 3; i++)
          ideq.push_back(i);
  
      for (int i = 0; i < ideq.size(); ++i)
          cout << ideq[i] << ' ';
      cout << endl;
      cout << "size=" << ideq.size() << endl;
  
      ideq.push_back(3);
      for (int i = 0; i < ideq.size(); ++i)
          cout << ideq[i] << ' ';
      cout << endl;
      cout << "size=" << ideq.size() << endl;
  
      ideq.push_front(99);
      for (int i = 0; i < ideq.size(); ++i)
          cout << ideq[i] << ' ';
      cout << endl;
      cout << "size=" << ideq.size() << endl;
  
      ideq.push_front(98);
      ideq.push_front(97);
      for (int i = 0; i < ideq.size(); ++i)
          cout << ideq[i] << ' ';
      cout << endl;
      cout << "size=" << ideq.size() << endl;
  
      deque<int>::iterator it = find(ideq.begin(), ideq.end(), 99);
      cout << *it << endl;
      
      system("pause");
      return 0;
  }
  

猜你喜欢

转载自blog.csdn.net/u012940886/article/details/80529721