您的位置:首页 > 产品设计 > UI/UE

STL学习——Deque篇

2016-05-06 22:10 561 查看

STL学习——Deque篇

deque概述

deque是一种双向开口的连续线性空间。双向开口指可以在头尾两端分别做元素的插入和删除操作。虽然vector也可以在头尾两端进行操作,但是其头部操作效率极差,无法被接受。

deque与vector最大差异:1)deque允许于常数时间内对起头端进行元素的插入或移除操作;2)deque没有所谓的容量概念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并连接起来。deque不提供所谓的空间保留功能,不存在重新配置,移动数据,释放原空间操作。

deque提供Random Access Iterator,但它的迭代器指针不是普通指针。deque复杂度大,故对deque进行操作,为了最高效率,可将deque先完整复制到一个vector上,然后将vector排序,在复制回deque。

deque中控器

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

deque实现复杂:因为分段连续线性空间,需要有中央控制,为了维持整体连续假象,数据结构的设计及迭代器前进后退等操作都非常繁琐。

deque采用一块所谓的map作为主控。此处的map是一小块连续空间,其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的存储空间主体。SGI STL中缓冲区大小可以指定,默认情况下缓冲区大小为512 bytes。

在源码实现中,map实质是T,即指针的指针**。下面是deque的部分定义

template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class deque : protected _Deque_base<_Tp, _Alloc> {
__STL_CLASS_REQUIRES(_Tp, _Assignable);

typedef _Deque_base<_Tp, _Alloc> _Base;
public:                         // 基本类型
typedef _Tp value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;

typedef typename _Base::allocator_type allocator_type;
allocator_type get_allocator() const { return _Base::get_allocator(); }

public:                         // 迭代器
typedef typename _Base::iterator       iterator;
typedef typename _Base::const_iterator const_iterator;

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
typedef reverse_iterator<const_iterator, value_type, const_reference,
difference_type>
const_reverse_iterator;
typedef reverse_iterator<iterator, value_type, reference, difference_type>
reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

protected:                      // 内部类型
typedef pointer* _Map_pointer;// 元素的指针的指针(pointer of pointer of T)
static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }

protected:
#ifdef __STL_USE_NAMESPACES
using _Base::_M_initialize_map;
using _Base::_M_create_nodes;
using _Base::_M_destroy_nodes;
using _Base::_M_allocate_node;
using _Base::_M_deallocate_node;
using _Base::_M_allocate_map;
using _Base::_M_deallocate_map;

using _Base::_M_map;           // 指向map,map是块连续的空间,其内的每个元素都是一个指针(称为节点),指向一块缓冲区
using _Base::_M_map_size;      // map内可容纳多少指针
using _Base::_M_start;         // 表现第一个节点
using _Base::_M_finish;        // 表现最后一个节点
#endif /* __STL_USE_NAMESPACES */
...
};


deque迭代器

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

deque数据结构满足条件:1)必须能够指出分段连续空间(亦即缓冲区)在哪里;2)必须判断自己是否已经处于其所在缓冲区的边缘,如果是,一旦前进或后退时,就必须跳跃至下一个或上一个缓冲区。为了能够跳跃,deque必须随时掌握管控中心(map)。

// 其中用来决定缓冲区大小的函数buffer_size(),调用__deque_buf_size(),后者是一个全局函数,定义如下:
// 如果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 __size) {
return __size < 512 ? size_t(512 / __size) : size_t(1);
}

template <class _Tp, class _Ref, class _Ptr>
struct _Deque_iterator {        // 未继承std::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)); }

// 未继承 std::iterator,所以必须自行撰写五个必要的迭代器相应型别
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;

typedef _Deque_iterator _Self;

// 保持与容器的联结
_Tp* _M_cur;            // 此迭代器所指之缓冲区的现行(current)元素
_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<>成功运作的关键。
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个距离
_Self& operator+=(difference_type __n)
{
difference_type __offset = __n + (_M_cur - _M_first);
if (__offset >= 0 && __offset < difference_type(_S_buffer_size()))
_M_cur += __n;    // 目标位置在同一缓冲区内
else {              // 目标位置不在同一缓冲区内
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;
return __tmp += __n;        // 调用operator+=
}
// 将n变为-n就可以使用operator+=()函数实现operator-=()操作
_Self& operator-=(difference_type __n) { return *this += -__n; }

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

// 以下实现随机存取。迭代器可以直接跳跃n个距离
reference operator[](difference_type __n) const { return *(*this + __n); }   // 调用operator*, operator+

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); }

// deque在进行加,减等操作时,遇到缓冲区边缘,需视前进或后退而定,可能需要调用set_node()跳过一个缓冲区。
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());
}
};


deque数据结构

deque不仅需要维护一个map的指针,还需要维护start,finish两个迭代器,分别指向第一缓冲区的第一个元素和最后一个缓冲区的最后一个元素(的下一个位置)。此外,还需记住当前map大小,用于当map节点不足时,配置更大的一块map。

// deque成员变量
using _Base::_M_map;           // 指向map,map是块连续的空间,其内的每个元素都是一个指针(称为节点),指向一块缓冲区
using _Base::_M_map_size;      // map内可容纳多少指针
using _Base::_M_start;         // 表现第一个节点
using _Base::_M_finish;        // 表现最后一个节点
// 部分基本操作
reference front() { return *_M_start; }   // 调用__deque_iterator<>::operator[]
reference back() {
iterator __tmp = _M_finish;
--__tmp;
return *__tmp;
}
const_reference front() const { return *_M_start; }
const_reference back() const {
const_iterator __tmp = _M_finish;
--__tmp;           // 调用__deque_iterator<>::operator--
return *__tmp;     // 调用__deque_iterator<>::operator*
// 以上三行何不改为:return *(finish-1),因为__deque_iterator<>没有为(finish-1)定义运算子
}
// 当前元素拥有的元素个数,调用了迭代器重载的operator-操作
size_type size() const { return _M_finish - _M_start; }   // 调用iterator::operator-
size_type max_size() const { return size_type(-1); }
// 判断deque是否为空,只有一个缓冲区
bool empty() const { return _M_finish == _M_start; }


deque构造与内存管理

deque的缓冲区扩充比较繁琐。deque内部定义了两个专属的空间配置器,其详细分析见下面源码。

template <class _Tp, class _Alloc>
class _Deque_base {
public:
typedef _Deque_iterator<_Tp,_Tp&,_Tp*>             iterator;
typedef _Deque_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;

typedef _Alloc allocator_type;
allocator_type get_allocator() const { return allocator_type(); }

_Deque_base(const allocator_type&, size_t __num_elements)
: _M_map(0), _M_map_size(0),  _M_start(), _M_finish() {
_M_initialize_map(__num_elements);
}
_Deque_base(const allocator_type&)
: _M_map(0), _M_map_size(0),  _M_start(), _M_finish() {}
~_Deque_base();

protected:
void _M_initialize_map(size_t);
void _M_create_nodes(_Tp** __nstart, _Tp** __nfinish);
void _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish);
enum { _S_initial_map_size = 8 };

protected:
_Tp** _M_map;          // 双指针,用于控制中央控制器map
size_t _M_map_size;
iterator _M_start;
iterator _M_finish;

typedef simple_alloc<_Tp, _Alloc>  _Node_alloc_type;    // 专属之空间配置器,每次配置一个元素大小
typedef simple_alloc<_Tp*, _Alloc> _Map_alloc_type;     // 专属之空间配置器,每次配置一个指针大小

_Tp* _M_allocate_node()
{ return _Node_alloc_type::allocate(__deque_buf_size(sizeof(_Tp))); }
void _M_deallocate_node(_Tp* __p)
{ _Node_alloc_type::deallocate(__p, __deque_buf_size(sizeof(_Tp))); }
_Tp** _M_allocate_map(size_t __n)
{ return _Map_alloc_type::allocate(__n); }
void _M_deallocate_map(_Tp** __p, size_t __n)
{ _Map_alloc_type::deallocate(__p, __n); }
};

// 主要用于安排好deque结构
template <class _Tp, class _Alloc>
void
_Deque_base<_Tp,_Alloc>::_M_initialize_map(size_t __num_elements)
{
// 需要节点数=(元素个数/每个缓冲区可容纳的元素个数)+1
// 如果刚好整除,会多分配一个节点
size_t __num_nodes =
__num_elements / __deque_buf_size(sizeof(_Tp)) + 1;
// 一个map要管理几个节点。最少8个,最多是“所需节点数加2”(前后各预留一个,会多配一个节点)
_M_map_size = max((size_t) _S_initial_map_size, __num_nodes + 2);
_M_map = _M_allocate_map(_M_map_size);
// 以下令nstart和nfinish指向map所拥有之全部节点的最中央区段
// 保持在最中央,可使头尾两端的扩充能量一样大。每个节点可对应一个缓冲区
_Tp** __nstart = _M_map + (_M_map_size - __num_nodes) / 2;
_Tp** __nfinish = __nstart + __num_nodes;

__STL_TRY {
// 为map内的每个现用节点配置缓冲区。所有缓冲区加起来就是deque的可用空间(最后一个缓冲区可能留有一些富裕)
_M_create_nodes(__nstart, __nfinish);
}
__STL_UNWIND((_M_deallocate_map(_M_map, _M_map_size),
_M_map = 0, _M_map_size = 0));
// 为deque内的两个迭代器start和end设定正确内容
_M_start._M_set_node(__nstart);
_M_finish._M_set_node(__nfinish - 1);
_M_start._M_cur = _M_start._M_first;          // first,cur都是public
_M_finish._M_cur = _M_finish._M_first +
__num_elements % __deque_buf_size(sizeof(_Tp));
// 前面说过,如果刚好整除,会多分配一个节点
// 此时即令cur指向这多配的一个节点(所对映值缓冲区)的起始处
}

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);
}

// 先配置一整块新的缓冲区,再设妥新元素内容,然后更改迭代器finish的状态
// 只有当finish.cur == finish.last - 1时才会被调用
// 即,只有当最后一个缓冲区只剩下一个备用元素空间时才会被调用
template <class _Tp, class _Alloc>
void deque<_Tp,_Alloc>::_M_push_back_aux(const value_type& __t)
{
value_type __t_copy = __t;
_M_reserve_map_at_back();                       // 若符合某种条件则必须重换一个map
*(_M_finish._M_node + 1) = _M_allocate_node();  // 配置一个新节点(缓冲区)
__STL_TRY {
construct(_M_finish._M_cur, __t_copy);        // 针对标的元素设值
_M_finish._M_set_node(_M_finish._M_node + 1); // 改变finish,令其指向新节点
_M_finish._M_cur = _M_finish._M_first;        // 设定finish的状态
}
__STL_UNWIND(_M_deallocate_node(*(_M_finish._M_node + 1)));
}

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);
}

// 当前状态下,第一缓冲区无备用空间。
// 只有当start.cur == start.first时才会被调用
// 也就是说,只有当第一个缓冲区没有任何备用元素时才会被调用
template <class _Tp, class _Alloc>
void  deque<_Tp,_Alloc>::_M_push_front_aux(const value_type& __t)
{
value_type __t_copy = __t;
_M_reserve_map_at_front();                     // 若符合某种条件则必须重换一个map
*(_M_start._M_node - 1) = _M_allocate_node();
__STL_TRY {
_M_start._M_set_node(_M_start._M_node - 1);  // 改变start,令其指向新节点
_M_start._M_cur = _M_start._M_last - 1;      // 设定start的状态
construct(_M_start._M_cur, __t_copy);        // 针对标的元素设值
}
__STL_UNWIND((++_M_start, _M_deallocate_node(*(_M_start._M_node - 1))));
}

void _M_reserve_map_at_back (size_type __nodes_to_add = 1) {
if (__nodes_to_add + 1 > _M_map_size - (_M_finish._M_node - _M_map))
// 如果map尾端的节点备用空间不足
// 符合以上条件则必须重换一个map(配置更大的,拷贝原来的,释放原来的)
_M_reallocate_map(__nodes_to_add, false);
}

void _M_reserve_map_at_front (size_type __nodes_to_add = 1) {
if (__nodes_to_add > size_type(_M_start._M_node - _M_map))
// 如果map前端的节点备用空间不足
// 符合以上条件则必须重换一个map(配置更大的,拷贝原来的,释放原来的)
_M_reallocate_map(__nodes_to_add, true);
}

template <class _Tp, class _Alloc>
void deque<_Tp,_Alloc>::_M_reallocate_map(size_type __nodes_to_add,
bool __add_at_front)
{
size_type __old_num_nodes = _M_finish._M_node - _M_start._M_node + 1;
size_type __new_num_nodes = __old_num_nodes + __nodes_to_add;

_Map_pointer __new_nstart;
if (_M_map_size > 2 * __new_num_nodes) {
__new_nstart = _M_map + (_M_map_size - __new_num_nodes) / 2
+ (__add_at_front ? __nodes_to_add : 0);
if (__new_nstart < _M_start._M_node)
copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart);
else
copy_backward(_M_start._M_node, _M_finish._M_node + 1,
__new_nstart + __old_num_nodes);
}
else {
size_type __new_map_size =
_M_map_size + max(_M_map_size, __nodes_to_add) + 2;

_Map_pointer __new_map = _M_allocate_map(__new_map_size);         // 配置一块空间,准备给新map使用
__new_nstart = __new_map + (__new_map_size - __new_num_nodes) / 2
+ (__add_at_front ? __nodes_to_add : 0);
copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart);      // 把原map内容拷贝过来
_M_deallocate_map(_M_map, _M_map_size);                           // 释放原map

_M_map = __new_map;                                               // 设置新map的起始地址和大小
_M_map_size = __new_map_size;
}

_M_start._M_set_node(__new_nstart);                                 // 重新设定迭代器start和finish
_M_finish._M_set_node(__new_nstart + __old_num_nodes - 1);
}


deque基本操作

deque的基本操作主要有pop_back,pop_front,clear,erase,insert等。

// pop为将元素拿掉,包括从最前端和最尾端取元素。注意某些条件下,需要释放缓冲区。
void pop_back() {
if (_M_finish._M_cur != _M_finish._M_first) {   // 最后缓冲区有一个(或更多)元素
--_M_finish._M_cur;                           // 调整指针,相当于排除了最后元素
destroy(_M_finish._M_cur);                    // 将最后元素析构
}
else                                            // 最后缓冲区没有任何元素
_M_pop_back_aux();                            // 这里将进行缓冲区的释放工作
}
// 只有当finish.cur == finish.first时才会被调用
template <class _Tp, class _Alloc>
void deque<_Tp,_Alloc>::_M_pop_back_aux()
{
_M_deallocate_node(_M_finish._M_first);        // 释放最后一个缓冲区
_M_finish._M_set_node(_M_finish._M_node - 1);  // 调整finish的状态,使指向上一个缓冲区的最后一个元素
_M_finish._M_cur = _M_finish._M_last - 1;
destroy(_M_finish._M_cur);                     // 析构该元素
}

void pop_front() {
if (_M_start._M_cur != _M_start._M_last - 1) {  // 第一个缓冲区有两个(或更多)元素
destroy(_M_start._M_cur);                     // 将第一个元素析构
++_M_start._M_cur;                            // 调整指针,相当于排除了第一个元素
}
else                                            // 第一个缓冲区仅有一个元素
_M_pop_front_aux();                           // 这里讲进行缓冲区的释放工作
}
// 只有当start.cur == start.las - 1时才会被调用
template <class _Tp, class _Alloc>
void deque<_Tp,_Alloc>::_M_pop_front_aux()
{
destroy(_M_start._M_cur);                       // 将第一缓冲区的第一个元素(也就是最后一个、唯一一个)元素析构
_M_deallocate_node(_M_start._M_first);          // 释放第一缓冲区
_M_start._M_set_node(_M_start._M_node + 1);     // 调整start的状态,使指向下一个缓冲区的第一个元素
_M_start._M_cur = _M_start._M_first;
}

// 清除整个deque。注意:deque的最初状态(无任何元素时)保有一个缓冲区,因此,clear()完成之后恢复初始状态,
// 即也要保留一个缓冲区
template <class _Tp, class _Alloc>
void deque<_Tp,_Alloc>::clear()
{
for (_Map_pointer __node = _M_start._M_node + 1;   // 针对头尾外的每个缓冲区(它们一定都是饱满的)
__node < _M_finish._M_node;
++__node) {
destroy(*__node, *__node + _S_buffer_size());    // 将缓冲区内的所有元素析构
_M_deallocate_node(*__node);                     // 释放缓冲区内存
}

if (_M_start._M_node != _M_finish._M_node) {       // 至少有头尾两个缓冲区
destroy(_M_start._M_cur, _M_start._M_last);      // 将头缓冲区的目前所有元素析构
destroy(_M_finish._M_first, _M_finish._M_cur);   // 将尾缓冲区的目前所有元素析构
_M_deallocate_node(_M_finish._M_first);          // 释放尾缓冲区。注意:头缓冲区保留
}
else                                               // 只有一个缓冲区
destroy(_M_start._M_cur, _M_finish._M_cur);      // 将此唯一缓冲区内的所有元素析构
// 注意,并不释放缓冲区空间。这唯一的缓冲区将保留
_M_finish = _M_start;                              // 调整状态
}

// 清除pos所指的元素。pos为清除点
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;
}

// 清除[first, last)区间内的所有元素
template <class _Tp, class _Alloc>
typename deque<_Tp,_Alloc>::iterator
deque<_Tp,_Alloc>::erase(iterator __first, iterator __last)
{
if (__first == _M_start && __last == _M_finish) {   // 如果清除区间就是整个deque
clear();                                          // 直接调用clear()即可
return _M_finish;
}
else {
difference_type __n = __last - __first;                            // 清除区间的长度
difference_type __elems_before = __first - _M_start;               // 清除区间前方的元素个数
if (__elems_before < difference_type((this->size() - __n) / 2)) {  // 如果前方的元素比较少
copy_backward(_M_start, __first, __last);                        // 向后移动前方元素(覆盖清除区间)
iterator __new_start = _M_start + __n;                           // 标记deque的新起点
destroy(_M_start, __new_start);                                  // 移动完毕,将冗余的元素析构
_M_destroy_nodes(__new_start._M_node, _M_start._M_node);         // 将冗余的缓冲区释放
_M_start = __new_start;                                          // 设定deque的新起点
}
else {                                                             // 如果清除区间后的元素比较少
copy(__last, _M_finish, __first);                                // 向前移动前方元素(覆盖清除区间)
iterator __new_finish = _M_finish - __n;                         // 标记deque的新起点
destroy(__new_finish, _M_finish);                                // 移动完毕,将冗余的元素析构
_M_destroy_nodes(__new_finish._M_node + 1, _M_finish._M_node + 1); // 释放冗余的缓冲区
_M_finish = __new_finish;                                        // 设定deque的新尾点
}
return _M_start + __elems_before;
}
}

// 在position处插入一个元素,其值为x
iterator insert(iterator position, const value_type& __x) {
if (position._M_cur == _M_start._M_cur) {         // 如果插入点是deque最前端
push_front(__x);                                // 交给push_front去做
return _M_start;
}
else if (position._M_cur == _M_finish._M_cur) {   // 如果插入点是deque最尾端
push_back(__x);                                 // 交给push_back去做
iterator __tmp = _M_finish;
--__tmp;
return __tmp;
}
else {
return _M_insert_aux(position, __x);            // 交给insert_aux去做
}
}
// 插入辅助函数
template <class _Tp, class _Alloc>
typename deque<_Tp, _Alloc>::iterator
deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos, const value_type& __x)
{
difference_type __index = __pos - _M_start;    // 插入点之前的元素个数
value_type __x_copy = __x;
if (size_type(__index) < this->size() / 2) {   // 如果插入点之前的元素个数比较少
push_front(front());                         // 在最前端加入与第一元素同值的元素
iterator __front1 = _M_start;                // 以下标示标记,然后进行元素移动
++__front1;
iterator __front2 = __front1;
++__front2;
__pos = _M_start + __index;
iterator __pos1 = __pos;
++__pos1;
copy(__front2, __pos1, __front1);            // 元素移动
}
else {                                         // 插入点之后的元素个数比较少
push_back(back());                           // 在最尾端加入与最后元素同值的元素
iterator __back1 = _M_finish;                // 以下标示记号,然后进行元素移动
--__back1;
iterator __back2 = __back1;
--__back2;
__pos = _M_start + __index;
copy_backward(__pos, __back2, __back1);      // 元素移动
}
*__pos = __x_copy;                             // 再插入点上设定新值
return __pos;
}


参考文献

STL源码剖析——侯捷

STL源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  stl deque 双端队列