STL源码—deque

 deque是一种双向开口的分段连续线性空间,可以在头尾端进行元素的插入和删除。

deque与vector最大的差异就是:

deque允许于常数时间内对头端进行插入或删除元素;

deque是分段连续线性空间,随时可以增加一段新的空间;deque不像vector那样,vector当内存不够时,需重新分配/复制数据/释放原始空间;

不过deque的迭代器设置比vector复杂,因为迭代器不能使用普通指针,因此尽量使用vector; 当对deque的元素进行排序时,为了提高效率,首先把deque数据复制到vector,利用vector的排序算法(利用STLsort算法),排序之后再次复制回deque;

1:deque中控器

因为deque的空间是连续线性空间,所以需要一个中控器进行管理,deque对外的接口类似于连续空间,为了管理这些分段空间deque容器引进了map,和stl中的map,不是同一个概念,map是一小块连续的空间其中每个元素都是指向缓冲区的指针,缓冲区才是存储数据的主体



2:deque迭代器

 deque是分段连续的线性空间,则普通指针不能作为deque的迭代器。迭代器设计时必须能够进行 operator++ operator-- 操作,为了能够是用户随机访问容器,则必须对操作符进行重载。
      deque迭代器的功能
  1. 必须知道缓冲区的位置
  2. 能够判断是否处于其所在缓冲区的边界
  3. 能够知道其所在缓冲区当前所指位置的元素
   迭代器的数据结构如下:

[cpp]  view plain copy
  1. struct _Deque_iterator {  
  2.     ...  
  3.    //以下是迭代器设计的关键,访问容器的节点  
  4.   _Tp* _M_cur;//指向缓冲区当前的元素  
  5.   _Tp* _M_first;//指向缓冲区的头(起始地址)  
  6.   _Tp* _M_last;//指向缓冲区的尾(结束地址)  
  7.   _Map_pointer _M_node;//指向中控器的相应节点  
  8.   ...  
  9. };  

下面是迭代器的一些算法,同时是一些迭代器计算方法

//*	deque是分段连续线性空间,为了能够像连续线性空间那样访问数据,
//*	deque采用了一种中控方法map,map是块连续的空间,其每个元素都是一个指针,
//*	指向一块缓冲区,实质上map是T**;
//***************************************************************


//这个函数是方便不同编译器处理常量表达式的bug,根据size的情况确定缓冲区大小
inline size_t __deque_buf_size(size_t __size) {
  return __size < 512 ? size_t(512 / __size) : size_t(1);
}

//deque迭代器的设计
//*deque是分段连续的线性空间,迭代器设计时必须能够进行operator++或operator--操作
//*	迭代器的功能:
//*	1、必须知道缓冲区的位置
//*	2、能够判断是否处于其所在缓冲区的边界
//*	3、能够知道其所在缓冲区当前所指位置的元素
//********************************************
template <class _Tp, class _Ref, class _Ptr>
struct _Deque_iterator {
  typedef _Deque_iterator<_Tp, _Tp&, _Tp*>             iterator;
  typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
  static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }

  typedef random_access_iterator_tag iterator_category;
  typedef _Tp value_type;
  typedef _Ptr pointer;
  typedef _Ref reference;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef _Tp** _Map_pointer; //<map是双重指针

  typedef _Deque_iterator _Self;

  //以下是迭代器设计的关键,访问容器的节点
  _Tp* _M_cur;//指向缓冲区当前的元素
  _Tp* _M_first;//指向缓冲区的头(起始地址)
  _Tp* _M_last;//指向缓冲区的尾(结束地址)
  _Map_pointer _M_node;//指向中控器的相应节点

  _Deque_iterator(_Tp* __x, _Map_pointer __y) 
    : _M_cur(__x), _M_first(*__y),
      _M_last(*__y + _S_buffer_size()), _M_node(__y) {}
  _Deque_iterator() : _M_cur(0), _M_first(0), _M_last(0), _M_node(0) {}
  _Deque_iterator(const iterator& __x)
    : _M_cur(__x._M_cur), _M_first(__x._M_first), 
      _M_last(__x._M_last), _M_node(__x._M_node) {}

  //*	迭代器_Deque_iterator的操作这些操作符的重载方便我们访问容器的内容
  //*	也是让deque从接口看来是维护连续线性空间的关键
  //****************************************************************************
  reference operator*() const { return *_M_cur; }//解除引用,返回当前元素
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return _M_cur; }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

  //返回两个迭代器之间的距离
  difference_type operator-(const _Self& __x) const {
    return difference_type(_S_buffer_size()) * (_M_node - __x._M_node - 1) +
      (_M_cur - _M_first) + (__x._M_last - __x._M_cur);
  }

  //前缀自增++操作符重载
  _Self& operator++() {
    ++_M_cur;					//普通自增操作,移至下一个元素
    if (_M_cur == _M_last) {   //若已达到缓冲区的尾部
      _M_set_node(_M_node + 1);//切换至下一缓冲区(节点)
      _M_cur = _M_first;	  //的第一个元素
    }
    return *this;
  }
  //后缀自增++操作符重载
  //返回当前迭代器的一个副本
  _Self operator++(int)  {
    _Self __tmp = *this;//定义当前迭代器的一个副本
    ++*this;//这里前缀++不是普通的++操作,是上一步骤已经重载过的前缀++
    return __tmp;
  }

  //前缀自减--操作符重载
  //基本思想类似于前缀自增操作
  _Self& operator--() {
    if (_M_cur == _M_first) {  //若是当前缓冲区的第一个元素
      _M_set_node(_M_node - 1);//切换到上一个缓冲区
      _M_cur = _M_last;		  //的尾部(即最后一个元素的下一个位置)
    }
    --_M_cur;//普通的自减操作,移至前一个元素
    return *this;
  }
  //后缀自减--操作符重载
  //返回当前迭代器的副本
  _Self operator--(int) {
    _Self __tmp = *this;//定义一个副本
    --*this;			//迭代器自减操作
    return __tmp;
  }

  //以下实现随机存取,迭代器可以直接跳跃n个距离
  //将迭代器前移n个距离,当n负值时就为下面的operator-=操作
  _Self& operator+=(difference_type __n)
  {
    difference_type __offset = __n + (_M_cur - _M_first);//定义一个中间变量
    if (__offset >= 0 && __offset < difference_type(_S_buffer_size()))
		//若前移n个距离后,目标依然在同一个缓冲区
		//则直接前移n个距离
      _M_cur += __n;
    else {
		//若前移n个距离后,目标超出该缓冲区范围
		//__offset / difference_type(_S_buffer_size())计算向后移动多少个缓冲区
		//-difference_type((-__offset - 1) / _S_buffer_size()) - 1计算向前移动多少个缓冲区
      difference_type __node_offset =
        __offset > 0 ? __offset / difference_type(_S_buffer_size())
                   : -difference_type((-__offset - 1) / _S_buffer_size()) - 1;
	  //调整到正确的缓冲区
      _M_set_node(_M_node + __node_offset);
	  //切换至正确的元素
      _M_cur = _M_first + 
        (__offset - __node_offset * difference_type(_S_buffer_size()));
    }
    return *this;
  }

  //操作符+重载
  //返回操作之后的副本
  _Self operator+(difference_type __n) const
  {
    _Self __tmp = *this;
	//调用operator+=操作
    return __tmp += __n;
  }

  //利用operator+=操作实现
  _Self& operator-=(difference_type __n) { return *this += -__n; }
 
  _Self operator-(difference_type __n) const {
    _Self __tmp = *this;
    return __tmp -= __n;
  }

  //返回指定位置的元素,即实现随机存取
  //该函数调用operator+,operator*
  reference operator[](difference_type __n) const { return *(*this + __n); }

  bool operator==(const _Self& __x) const { return _M_cur == __x._M_cur; }
  bool operator!=(const _Self& __x) const { return !(*this == __x); }
  bool operator<(const _Self& __x) const {
    return (_M_node == __x._M_node) ? 
      (_M_cur < __x._M_cur) : (_M_node < __x._M_node);
  }
  bool operator>(const _Self& __x) const  { return __x < *this; }
  bool operator<=(const _Self& __x) const { return !(__x < *this); }
  bool operator>=(const _Self& __x) const { return !(*this < __x); }

  //调整到正确的缓冲区
  //切换到正确的元素位置
  void _M_set_node(_Map_pointer __new_node) {
    _M_node = __new_node;//指向新的节点
    _M_first = *__new_node;//指向新节点的头部
    _M_last = _M_first + difference_type(_S_buffer_size());//指向新节点的尾部
  }
};

3:deque的数据结构:

deque除了维护先前的一个先前说过的指向map的指针外,也维护一个start,finish两个迭代器,分别指向第一缓冲区的第一个元素和最后缓冲区的最后一个元素,同时需要记住map大小,因为一旦map所提供的节点不足,就必须重新分配更大的一块map


template <class _Tp, class _Alloc>
class _Deque_base {
	...
protected:
  _Tp** _M_map;
  size_t _M_map_size;  
  iterator _M_start;
  iterator _M_finish;
  ...
};
//deque容器的定义
//配置器默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class deque : protected _Deque_base<_Tp, _Alloc> {

  // requirements:

  ...

public:                         // Iterators
  typedef typename _Base::iterator       iterator;
  typedef typename _Base::const_iterator const_iterator;

protected:

  //下面是deque的数据结构
  using _Base::_M_map;//指向中控器map
  using _Base::_M_map_size;//map内指针的个数
  using _Base::_M_start;//指向第一个节点
  using _Base::_M_finish;//指向最后一个节点
  ...
};


4:deque部分成员函数简介

 void swap(deque& __x) {  
    __STD::swap(_M_start, __x._M_start);  
    __STD::swap(_M_finish, __x._M_finish);  
    __STD::swap(_M_map, __x._M_map);  
    __STD::swap(_M_map_size, __x._M_map_size);  
  }  


  void push_back(const value_type& __t) {  
    //若当前缓冲区存在可用空间  
    if (_M_finish._M_cur != _M_finish._M_last - 1) {  
      construct(_M_finish._M_cur, __t);//直接构造对象  
      ++_M_finish._M_cur;//调整指针所指位置  
    }  
    else//若当前缓冲区不存在可用空间  
        //需分配一段新的连续空间  
      _M_push_back_aux(__t);  
  }  

void push_front(const value_type& __t) {  
    if (_M_start._M_cur != _M_start._M_first) {  
      construct(_M_start._M_cur - 1, __t);  
      --_M_start._M_cur;  
    }  
    else  
      _M_push_front_aux(__t);   //<第一个缓冲区中内存不够,需要重新分配空间
  }  

 iterator insert(iterator position, const value_type& __x) {  
    if (position._M_cur == _M_start._M_cur) {//若当前位置为deque.begin()  
      push_front(__x);//则在容器头部插入数据  
      return _M_start;  
    }  
    else if (position._M_cur == _M_finish._M_cur) {//若当前位置为deque.end()  
      push_back(__x);  
      iterator __tmp = _M_finish;  
      --__tmp;  
      return __tmp;  
    }  
    else {//否则在容器直接插入数据  
      return _M_insert_aux(position, __x);  
    }  
  }  

 //改变容器大小  
  void resize(size_type __new_size, const value_type& __x) {  
    const size_type __len = size();  
    if (__new_size < __len)//新的大小较旧的小   
      erase(_M_start + __new_size, _M_finish);//擦除多余的元素  
    else//否则,填充新增的节点  
      insert(_M_finish, __new_size - __len, __x);  
  }  
  
  void resize(size_type new_size) { resize(new_size, value_type()); }  
  
public:            
        //********************************************************  
        /*  擦除指定位置的元素  
        *   iterator erase (iterator position);  
        *   擦除指定区间的元素  
        *   iterator erase (iterator first, iterator last);  
        */  
        //********************************************************  
                                        // Erase  
  iterator erase(iterator __pos) {  
    iterator __next = __pos;  
    ++__next;  
    difference_type __index = __pos - _M_start;//擦除点之前元素个数  
    if (size_type(__index) < (this->size() >> 1)) {//若擦除点之前的元素个数较少  
      copy_backward(_M_start, __pos, __next);//向后移动擦除点之前的元素  
      pop_front();  
    }  
    else {  
      copy(__next, _M_finish, __pos);//否则,向前移动擦除点之后的元素  
      pop_back();  
    }  
    return _M_start + __index;  
  }  




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值