C++ STL:deque

1 deque概述 双端队列

vector是单向开口的连续线性空间, list是不连续空间, deque是双向开口的连续空间:双向开口就是头尾都可以插入删除元素

vector虽然是可以扩容,但是其扩容是先分配再复制后释放,但是deque允许在常数时间内在头和尾插入删除元素,deque没有容量的概念,无capacity有size, 是由分段连续空间构成的,那么deque的重点就是,如何在操作中保持分段连续空间的连接

vector的迭代器是支持随机访问的普通指针,虽然deque也支持随机访问,但不是普通指针

尽可能选择vector,对deque排序可以先复制到vector中排序

2 deque中控器

逻辑上连续空间,实际上分段连续空间,通过中控器map达到连续空间的假象,map也是一小段连续空间,每个元素node都是一个指针,指向一个较大的连续空间,称为缓冲区,缓冲区才是存储数据的主体,默认是512bytes.
在这里插入图片描述

template<class T, class Alloc= alloc, size_t buffer_size=0>
class deque
{
    typedef T value_type;
    typedef value_type* pointer;
    typedef pointer* map_pointer;
    map_pointer map; //T** 指针的指针
    size_type map_size;
}

3 deque迭代器

deque的迭代器应该能判断自己是否处于缓冲区的边缘,能够跳转到上一个或者下一个缓冲区

迭代器最重要的操作就是operator++ 和operator-- 以及set_node()

    _Elt_pointer _M_cur; //cur 指向当前缓冲区中的先行元素
    _Elt_pointer _M_first;//指向当前缓冲区的开头
    _Elt_pointer _M_last;//指向当前缓冲区的结尾
    _Map_pointer _M_node;//指向中控节点的当前缓冲区

    //下面直接复制源码 + 注释

     reference
      operator*() const _GLIBCXX_NOEXCEPT //解引用, *cur
      { return *_M_cur; }

      pointer
      operator->() const _GLIBCXX_NOEXCEPT // ->
      { return _M_cur; }

      _Self&
      operator++() _GLIBCXX_NOEXCEPT // 后移一个元素
      {
	++_M_cur; 
	if (_M_cur == _M_last) //判断是否到达当前缓冲区的结尾
	  {
	    _M_set_node(_M_node + 1); //使用set_node跳转
	    _M_cur = _M_first;
	  }
	return *this;
      }

      _Self
      operator++(int) _GLIBCXX_NOEXCEPT //经典写法
      {
	_Self __tmp = *this;
	++*this;
	return __tmp;
      }

      _Self&
      operator--() _GLIBCXX_NOEXCEPT
      {
	if (_M_cur == _M_first) //同理判断是否在当前缓冲区de
	  {
	    _M_set_node(_M_node - 1);
	    _M_cur = _M_last;
	  }
	--_M_cur;
	return *this;
      }

      _Self
      operator--(int) _GLIBCXX_NOEXCEPT
      {
	_Self __tmp = *this;
	--*this;
	return __tmp;
      }

      _Self&
      operator+=(difference_type __n) _GLIBCXX_NOEXCEPT //随机访问
      {
	const difference_type __offset = __n + (_M_cur - _M_first);
	if (__offset >= 0 && __offset < difference_type(_S_buffer_size())) //在同一个缓冲区内
	  _M_cur += __n;
	else//不在同一个缓冲区内
	  {
	    const 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 _GLIBCXX_NOEXCEPT
      {
	_Self __tmp = *this;
	return __tmp += __n;
      }

      _Self&
      operator-=(difference_type __n) _GLIBCXX_NOEXCEPT
      { return *this += -__n; }

      _Self
      operator-(difference_type __n) const _GLIBCXX_NOEXCEPT
      {
	_Self __tmp = *this;
	return __tmp -= __n;
      }

      reference
      operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
      { return *(*this + __n); }

      /**
       *  Prepares to traverse new_node.  Sets everything except
       *  _M_cur, which should therefore be set by the caller
       *  immediately afterwards, based on _M_first and _M_last.
       */
      void
      _M_set_node(_Map_pointer __new_node) _GLIBCXX_NOEXCEPT //跳一个缓冲区
      {
	    _M_node = __new_node;
	    _M_first = *__new_node;
	    _M_last = _M_first + difference_type(_S_buffer_size());
      }

4 deque数据结构

struct _Deque_impl
      : public _Tp_alloc_type
      {
	_Map_pointer _M_map;  //T**的map指针
	size_t _M_map_size; //map大小
	iterator _M_start;//指向第一个缓冲区的第一个元素
	iterator _M_finish;//指向最后一个缓冲区的最后一个元素
      }
reference
      operator[](size_type __n) _GLIBCXX_NOEXCEPT
      {
	__glibcxx_requires_subscript(__n);
	return this->_M_impl._M_start[difference_type(__n)];
      }
reference
      front() _GLIBCXX_NOEXCEPT
      {
	__glibcxx_requires_nonempty();
	return *begin();//*strat
      }
reference
      back() _GLIBCXX_NOEXCEPT
      {
	__glibcxx_requires_nonempty();
	iterator __tmp = end();
	--__tmp;
	return *__tmp;//end()上一个元素
      }
      iterator
      begin() _GLIBCXX_NOEXCEPT
      { return this->_M_impl._M_start; } //start
      iterator
      end() _GLIBCXX_NOEXCEPT
      { return this->_M_impl._M_finish; }//finish

      size_type
      size() const _GLIBCXX_NOEXCEPT
      { return this->_M_impl._M_finish - this->_M_impl._M_start; } //finish - start

      /**  Returns the size() of the largest possible %deque.  */
      size_type
      max_size() const _GLIBCXX_NOEXCEPT
      { return _Alloc_traits::max_size(_M_get_Tp_allocator()); } 
      empty() const _GLIBCXX_NOEXCEPT
      { return this->_M_impl._M_finish == this->_M_impl._M_start; }//finish == start

5 deque内存构造

deque(size_type __n, const value_type& __value,
	    const allocator_type& __a = allocator_type())
      : _Base(__a, __n)
      { _M_fill_initialize(__value); }

      template <typename _Tp, typename _Alloc>
    void
    deque<_Tp, _Alloc>::
    _M_fill_initialize(const value_type& __value)
    {
      _Map_pointer __cur;
      __try
        {
          for (__cur = this->_M_impl._M_start._M_node;
	       __cur < this->_M_impl._M_finish._M_node;
	       ++__cur)//对每一个缓冲区设置为__value
            std::__uninitialized_fill_a(*__cur, *__cur + _S_buffer_size(),
					__value, _M_get_Tp_allocator());
          std::__uninitialized_fill_a(this->_M_impl._M_finish._M_first,
				      this->_M_impl._M_finish._M_cur,
				      __value, _M_get_Tp_allocator());//最后一个缓冲区除去备用空间设置缓冲区
        }
      __catch(...)
        {
          std::_Destroy(this->_M_impl._M_start, iterator(*__cur, __cur),
			_M_get_Tp_allocator());
          __throw_exception_again;
        }
    }

    //初始化map
    template<typename _Tp, typename _Alloc>
    void
    _Deque_base<_Tp, _Alloc>::
    _M_initialize_map(size_t __num_elements)
    {
      const size_t __num_nodes = (__num_elements/ __deque_buf_size(sizeof(_Tp))
				  + 1);//需要几个缓冲区,最少8个

      this->_M_impl._M_map_size = std::max((size_t) _S_initial_map_size,
					   size_t(__num_nodes + 2));
      this->_M_impl._M_map = _M_allocate_map(this->_M_impl._M_map_size);

      // For "small" maps (needing less than _M_map_size nodes), allocation
      // starts in the middle elements and grows outwards.  So nstart may be
      // the beginning of _M_map, but for small maps it may be as far in as
      // _M_map+3.

      _Map_pointer __nstart = (this->_M_impl._M_map
			       + (this->_M_impl._M_map_size - __num_nodes) / 2);//保持在map的中间,这样头尾插入删除都是差不多的
      _Map_pointer __nfinish = __nstart + __num_nodes;

      __try
	{ _M_create_nodes(__nstart, __nfinish); }
      __catch(...)
	{
	  _M_deallocate_map(this->_M_impl._M_map, this->_M_impl._M_map_size);
	  this->_M_impl._M_map = _Map_pointer();
	  this->_M_impl._M_map_size = 0;
	  __throw_exception_again;
	}
      //设置迭代器start finish
      this->_M_impl._M_start._M_set_node(__nstart);
      this->_M_impl._M_finish._M_set_node(__nfinish - 1);
      this->_M_impl._M_start._M_cur = _M_impl._M_start._M_first;
      this->_M_impl._M_finish._M_cur = (this->_M_impl._M_finish._M_first
					+ __num_elements
					% __deque_buf_size(sizeof(_Tp)));
    }

6 deque其他操作

6.1 push_back()

void
      push_back(const value_type& __x)
      {
	if (this->_M_impl._M_finish._M_cur
	    != this->_M_impl._M_finish._M_last - 1) //还有没有备用空间: 有
	  {
	    _Alloc_traits::construct(this->_M_impl,
				     this->_M_impl._M_finish._M_cur, __x);
	    ++this->_M_impl._M_finish._M_cur;//直接在当前缓冲区构造一个
	  }
	else
	  _M_push_back_aux(__x);//没有
      }


      //_M_push_back_aux(__x)
        template<typename _Tp, typename _Alloc>
#if __cplusplus >= 201103L
    template<typename... _Args>
      void
      deque<_Tp, _Alloc>::
      _M_push_back_aux(_Args&&... __args)
#else
      void
      deque<_Tp, _Alloc>::
      _M_push_back_aux(const value_type& __t)
#endif
      {
	_M_reserve_map_at_back();//map不够用就换一个map,见下面如何换map
	*(this->_M_impl._M_finish._M_node + 1) = this->_M_allocate_node();//重新分配一个node缓冲区
	__try
	  {
#if __cplusplus >= 201103L
	    _Alloc_traits::construct(this->_M_impl,
	                             this->_M_impl._M_finish._M_cur,
			             std::forward<_Args>(__args)...);//设置元素的值
#else
//重新设置finish迭代器的值
	    this->_M_impl.construct(this->_M_impl._M_finish._M_cur, __t);
#endif
	    this->_M_impl._M_finish._M_set_node(this->_M_impl._M_finish._M_node
						+ 1);//跳一个node
	    this->_M_impl._M_finish._M_cur = this->_M_impl._M_finish._M_first;
	  }
	__catch(...)
	  {
	    _M_deallocate_node(*(this->_M_impl._M_finish._M_node + 1));
	    __throw_exception_again;
	  }
      }

      //换map
      void
      _M_reserve_map_at_front(size_type __nodes_to_add = 1)
      {
	if (__nodes_to_add > size_type(this->_M_impl._M_start._M_node
				       - this->_M_impl._M_map))
	  _M_reallocate_map(__nodes_to_add, true); //类似于vector(连续空间):配置新空间 拷贝旧空间 释放旧空间
      }


      template <typename _Tp, typename _Alloc>
    void
    deque<_Tp, _Alloc>::
    _M_reallocate_map(size_type __nodes_to_add, bool __add_at_front)
    {
      const size_type __old_num_nodes
	= this->_M_impl._M_finish._M_node - this->_M_impl._M_start._M_node + 1; //计算旧的节点个数
      const size_type __new_num_nodes = __old_num_nodes + __nodes_to_add;//新节点个数

      _Map_pointer __new_nstart;
      if (this->_M_impl._M_map_size > 2 * __new_num_nodes)
	{
	  __new_nstart = this->_M_impl._M_map + (this->_M_impl._M_map_size
					 - __new_num_nodes) / 2
	                 + (__add_at_front ? __nodes_to_add : 0);
	  if (__new_nstart < this->_M_impl._M_start._M_node)
	    std::copy(this->_M_impl._M_start._M_node,
		      this->_M_impl._M_finish._M_node + 1,
		      __new_nstart);
	  else
	    std::copy_backward(this->_M_impl._M_start._M_node,
			       this->_M_impl._M_finish._M_node + 1,
			       __new_nstart + __old_num_nodes);
	}
      else
	{
	  size_type __new_map_size = this->_M_impl._M_map_size
	                             + std::max(this->_M_impl._M_map_size,
						__nodes_to_add) + 2;
      //配置一块新的空间
	  _Map_pointer __new_map = this->_M_allocate_map(__new_map_size);
	  __new_nstart = __new_map + (__new_map_size - __new_num_nodes) / 2
	                 + (__add_at_front ? __nodes_to_add : 0);
      //拷贝
	  std::copy(this->_M_impl._M_start._M_node,
		    this->_M_impl._M_finish._M_node + 1,
		    __new_nstart);
      //释放
	  _M_deallocate_map(this->_M_impl._M_map, this->_M_impl._M_map_size);

	  this->_M_impl._M_map = __new_map;
	  this->_M_impl._M_map_size = __new_map_size;
	}

      this->_M_impl._M_start._M_set_node(__new_nstart);
      this->_M_impl._M_finish._M_set_node(__new_nstart + __old_num_nodes - 1);
    }

6.2 push_front()

和push_back一样的,就是处理的是头部,就不再详细写了

void
      push_front(const value_type& __x)
      {
	if (this->_M_impl._M_start._M_cur != this->_M_impl._M_start._M_first)
	  {
	    _Alloc_traits::construct(this->_M_impl,
				     this->_M_impl._M_start._M_cur - 1,
				     __x);
	    --this->_M_impl._M_start._M_cur;
	  }
	else
	  _M_push_front_aux(__x);
      }

6.3 pop_back()

和push_back()差不多 看是否是在finish的头部,要删除缓冲区

 void
      pop_back() _GLIBCXX_NOEXCEPT
      {
	__glibcxx_requires_nonempty();
	if (this->_M_impl._M_finish._M_cur
	    != this->_M_impl._M_finish._M_first)//不在finish的头部
	  {
	    --this->_M_impl._M_finish._M_cur;
	    _Alloc_traits::destroy(this->_M_impl,
				   this->_M_impl._M_finish._M_cur);//删除当前元素即可
	  }
	else
	  _M_pop_back_aux(); //在:需要删除缓冲区
      }
       template <typename _Tp, typename _Alloc>
    void deque<_Tp, _Alloc>::
    _M_pop_back_aux()
    {
      _M_deallocate_node(this->_M_impl._M_finish._M_first);//删除finish节点缓冲区
      this->_M_impl._M_finish._M_set_node(this->_M_impl._M_finish._M_node - 1);//重新配置finish迭代器 向前跳一个
      this->_M_impl._M_finish._M_cur = this->_M_impl._M_finish._M_last - 1;
      _Alloc_traits::destroy(_M_get_Tp_allocator(),
			     this->_M_impl._M_finish._M_cur);
    }

6.4 pop_front()

和pop_back()差不多,就是看在不在start节点的最后一个 要是在就需要删除缓冲区

 void
      pop_front() _GLIBCXX_NOEXCEPT
      {
	__glibcxx_requires_nonempty();
	if (this->_M_impl._M_start._M_cur
	    != this->_M_impl._M_start._M_last - 1)
	  {
	    _Alloc_traits::destroy(this->_M_impl,
				   this->_M_impl._M_start._M_cur);
	    ++this->_M_impl._M_start._M_cur;
	  }
	else
	  _M_pop_front_aux();
      }

6.5 erase()

//清除一个元素po
template <typename _Tp, typename _Alloc>
    typename deque<_Tp, _Alloc>::iterator
    deque<_Tp, _Alloc>::
    _M_erase(iterator __position)
    {
      iterator __next = __position;
      ++__next;
      const difference_type __index = __position - begin();//清除点之前的元素个数
      if (static_cast<size_type>(__index) < (size() >> 1)) //清除点之前元素少:从前面删除
	{
	  if (__position != begin())
	    _GLIBCXX_MOVE_BACKWARD3(begin(), __position, __next); //move_backward 移动清除点之前的元素
	  pop_front();//删除最前面的元素
	}
      else
	{
	  if (__next != end())
	    _GLIBCXX_MOVE3(__next, end(), __position);//从后面删除
	  pop_back();
	}
      return begin() + __index;
    }
//清除一个区间 :和一个元素差不多 就是看看前面少还是后面少,在选择从前面删除还是后面
 template <typename _Tp, typename _Alloc>
    typename deque<_Tp, _Alloc>::iterator
    deque<_Tp, _Alloc>::
    _M_erase(iterator __first, iterator __last)
    {
      if (__first == __last)
	return __first;
      else if (__first == begin() && __last == end())
	{
	  clear();
	  return end();
	}
      else
	{
	  const difference_type __n = __last - __first;
	  const difference_type __elems_before = __first - begin();
	  if (static_cast<size_type>(__elems_before) <= (size() - __n) / 2)
	    {
	      if (__first != begin())
		_GLIBCXX_MOVE_BACKWARD3(begin(), __first, __last);
	      _M_erase_at_begin(begin() + __n);
	    }
	  else
	    {
	      if (__last != end())
		_GLIBCXX_MOVE3(__last, end(), __first);
	      _M_erase_at_end(end() - __n);
	    }
	  return begin() + __elems_before;
	}
    }

6.6 insert()


typename deque<_Tp, _Alloc>::iterator
      deque<_Tp, _Alloc>::
      _M_insert_aux(iterator __pos, const value_type& __x)
      {
	value_type __x_copy = __x; // XXX copy
#endif
	difference_type __index = __pos - this->_M_impl._M_start; //计算总长度
	if (static_cast<size_type>(__index) < size() / 2)  //前面短 从前面插入
	  {
	    push_front(_GLIBCXX_MOVE(front())); //先插入一个front()元素,再把后面的2-index-1 移过来,再加入pos
	    iterator __front1 = this->_M_impl._M_start;
	    ++__front1;
	    iterator __front2 = __front1;
	    ++__front2;
	    __pos = this->_M_impl._M_start + __index;
	    iterator __pos1 = __pos;
	    ++__pos1;
	    _GLIBCXX_MOVE3(__front2, __pos1, __front1);
	  }
	else//从后面插
	  {
	    push_back(_GLIBCXX_MOVE(back()));//先插入一个back(),再把后面index+1到-2移过来,再插入pos
	    iterator __back1 = this->_M_impl._M_finish;
	    --__back1;
	    iterator __back2 = __back1;
	    --__back2;
	    __pos = this->_M_impl._M_start + __index;
	    _GLIBCXX_MOVE_BACKWARD3(__pos, __back2, __back1);
	  }
	*__pos = _GLIBCXX_MOVE(__x_copy);
	return __pos;
      }

7 总结

deque是一个两端开口的假的连续空间,为了维持这个假象呢,他就需要付出代价,就是需要自己写迭代器、还要维护一个map,保持连续的状态。头和尾能进行的操作都是一样的,为了维持这样,map像一个端水大师,尽量从中间。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值