STL源码剖析 - 第4章 序列式容器 - deque
来源:互联网 发布:淘宝比价软件哪个好 编辑:程序博客网 时间:2024/05/21 22:43
4.4.1 deque概述
deue是一种双向开口的分段连续线性空间,可以在头尾端进行元素的插入和删除。
deque和vector最大的差异就是:
第一是deque允许于常数时间内对头端进行插入或删除元素;
第二是deque是分段连续线性空间,随时可以增加一段新的空间;deque不像vector那样,vector当内存不够时,需重新分配/复制数据/释放原始空间;不过deque的迭代器设置比vector复杂,因为迭代器不能使用普通指针,因此尽量使用vector; 当对deque的元素进行排序时,为了提高效率,首先把deque数据复制到vector,利用vector的排序算法(利用STL的sort算法),排序之后再次复制回deque;本文所列的源码出自SGI STL中的文件<stl_deque.h>,对于deque容器类的详细信息也可以查看《deque容器库》和《MSDN的deque类》
4.4.2 deque中控器
由于deque是分段连续线性空间的,即一段一段的定量连续空间构成。一旦有必要在deque的前端或者尾端增加新空间,便配置一段定量连续空间,串接在deque的头端或尾端。为了用户方便操作,所以它对外的接口类似于连续空间。为了管理这些分段空间deque容器引入了一种中控器map(不是stl的map容器),map是一块连续的空间,其中每个元素是指向缓冲区的指针,缓冲区才是deque存储数据的主体。下面给出map的结构;
_Tp** _M_map; size_t _M_map_size;
4.4.3 deque的迭代器
deque是分段连续的线性空间,则普通指针不能作为deque的迭代器。迭代器设计时必须能够进行operator++或operator--操作,为了能够是用户随机访问容器,则必须对操作符进行重载。
deque迭代器的功能:
1. 必须知道缓冲区的位置
2. 能够判断是否处于其所在缓冲区的边界
3. 能够知道其所在缓冲区当前所指位置的元素
迭代器的数据结构如下:
struct _Deque_iterator { ... //以下是迭代器设计的关键,访问容器的节点 _Tp* _M_cur;//指向缓冲区当前的元素 _Tp* _M_first;//指向缓冲区的头(起始地址) _Tp* _M_last;//指向缓冲区的尾(结束地址) _Map_pointer _M_node;//指向中控器的相应节点 ... };
为了实现能够随机访问,deque的中控器、缓冲区和迭代器之间的相互关系如下图所示:
以下是对迭代器源码的剖析:
//* deque是分段连续线性空间,为了能够像连续线性空间那样访问数据, //* deque采用了一种中控方法map,map是块连续的空间,其每个元素都是一个指针, //* 指向一块缓冲区,实质上map是T**; //*************************************************************** // Note: this function is simply a kludge to work around several compilers' // bugs in handling constant expressions. //这个函数是方便不同编译器处理常量表达式的bug 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; 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());//指向新节点的尾部 } };
4.4.4 deque容器的数据结构
deque容器具有维护map和迭代器的功能,deque定义的两个迭代器分别是start和finish,分别指向第一个缓冲区的第一个元素和最后一个缓冲区的最后一个元素的下一个位置;
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.4.5 deque容器的构造函数和析构函数
了解deque容器的构造函数和析构函数,方便我们使用;其源码如下:
public: //********************************************************** //* 以下是构造函数和析构函数 //* 默认构造函数 //* explicit deque( const Allocator& alloc = Allocator() ); //* 容器大小为count个初始值为value的元素 //* explicit deque( size_type count, //* const T& value = T(), //* const Allocator& alloc = Allocator()); //* deque( size_type count, //* const T& value, //* const Allocator& alloc = Allocator()); //* 容器大小为count个默认值的元素 //* explicit deque( size_type count ); //* 拷贝构造函数 //* deque( const deque& other ); //* deque( const deque& other, const Allocator& alloc ); //* 初始值为[first,last)内容的容器 //* template< class InputIt > //* deque( InputIt first, InputIt last, //* const Allocator& alloc = Allocator() ); //* 析构函数 //* ~deque() //* //******************************************************** // Constructor, destructor. explicit deque(const allocator_type& __a = allocator_type()) : _Base(__a, 0) {} deque(const deque& __x) : _Base(__x.get_allocator(), __x.size()) { uninitialized_copy(__x.begin(), __x.end(), _M_start); } deque(size_type __n, const value_type& __value, const allocator_type& __a = allocator_type()) : _Base(__a, __n) { _M_fill_initialize(__value); } explicit deque(size_type __n) : _Base(allocator_type(), __n) { _M_fill_initialize(value_type()); } #ifdef __STL_MEMBER_TEMPLATES // Check whether it's an integral type. If so, it's not an iterator. template <class _InputIterator> deque(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) { typedef typename _Is_integer<_InputIterator>::_Integral _Integral; _M_initialize_dispatch(__first, __last, _Integral()); } template <class _Integer> void _M_initialize_dispatch(_Integer __n, _Integer __x, __true_type) { _M_initialize_map(__n); _M_fill_initialize(__x); } template <class _InputIter> void _M_initialize_dispatch(_InputIter __first, _InputIter __last, __false_type) { _M_range_initialize(__first, __last, __ITERATOR_CATEGORY(__first)); } #else /* __STL_MEMBER_TEMPLATES */ deque(const value_type* __first, const value_type* __last, const allocator_type& __a = allocator_type()) : _Base(__a, __last - __first) { uninitialized_copy(__first, __last, _M_start); } deque(const_iterator __first, const_iterator __last, const allocator_type& __a = allocator_type()) : _Base(__a, __last - __first) { uninitialized_copy(__first, __last, _M_start); } #endif /* __STL_MEMBER_TEMPLATES */ ~deque() { destroy(_M_start, _M_finish); } //构造函数和析构函数定义结束
4.4.6 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); } public: // assign(), a generalized assignment member function. Two // versions: one that takes a count, and one that takes a range. // The range version is a member template, so we dispatch on whether // or not the type is an integer. void _M_fill_assign(size_type __n, const _Tp& __val) { if (__n > size()) {//若新的大小比容器原来的大 fill(begin(), end(), __val);//把原来容器填充为val insert(end(), __n - size(), __val);//容器追加填充值 } else {//若新的大小比容器原来的小 erase(begin() + __n, end());//则擦除多余的内容 fill(begin(), end(), __val);//填充值为val覆盖原来的内容 } } //对外接口的assign第一个版本 void assign(size_type __n, const _Tp& __val) { _M_fill_assign(__n, __val); } #ifdef __STL_MEMBER_TEMPLATES //对外接口的assign第二个版本 //采用迭代器的traist技术 template <class _InputIterator> void assign(_InputIterator __first, _InputIterator __last) { typedef typename _Is_integer<_InputIterator>::_Integral _Integral; _M_assign_dispatch(__first, __last, _Integral()); } private: // helper functions for assign() template <class _Integer> void _M_assign_dispatch(_Integer __n, _Integer __val, __true_type) { _M_fill_assign((size_type) __n, (_Tp) __val); } template <class _InputIterator> void _M_assign_dispatch(_InputIterator __first, _InputIterator __last, __false_type) { _M_assign_aux(__first, __last, __ITERATOR_CATEGORY(__first)); } template <class _InputIterator> void _M_assign_aux(_InputIterator __first, _InputIterator __last, input_iterator_tag); template <class _ForwardIterator> void _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, forward_iterator_tag) { size_type __len = 0; distance(__first, __last, __len);//计算两个输入迭代器的距离 if (__len > size()) {//若输入迭代器距离比待赋值容器大小还大 _ForwardIterator __mid = __first; advance(__mid, size());//将mid向前移动size()个距离 copy(__first, __mid, begin());//先复制[first,mid)数据 insert(end(), __mid, __last);//插入剩下的数据 } else//否则擦除多余的数据 erase(copy(__first, __last, begin()), end()); } #endif /* __STL_MEMBER_TEMPLATES */ public: // push_* and pop_* //在容器尾部加数据 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_back() { if (_M_finish._M_cur != _M_finish._M_last - 1) { construct(_M_finish._M_cur); ++_M_finish._M_cur; } else _M_push_back_aux(); } 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); } void push_front() { if (_M_start._M_cur != _M_start._M_first) { construct(_M_start._M_cur - 1); --_M_start._M_cur; } else _M_push_front_aux(); } 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(); } 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(); } public: //*********************************************************** /* 在指定位置之前插入数据 ************************************************************* * iterator insert (iterator position, const value_type& val); * * void insert (iterator position, size_type n, const value_type& val); * * template <class InputIterator> * void insert (iterator position, InputIterator first, InputIterator last); */ //*********************************************************** // Insert 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); } } iterator insert(iterator __position) { return insert(__position, value_type()); } void insert(iterator __pos, size_type __n, const value_type& __x) { _M_fill_insert(__pos, __n, __x); } void _M_fill_insert(iterator __pos, size_type __n, const value_type& __x); #ifdef __STL_MEMBER_TEMPLATES // Check whether it's an integral type. If so, it's not an iterator. template <class _InputIterator> void insert(iterator __pos, _InputIterator __first, _InputIterator __last) { typedef typename _Is_integer<_InputIterator>::_Integral _Integral; _M_insert_dispatch(__pos, __first, __last, _Integral()); } template <class _Integer> void _M_insert_dispatch(iterator __pos, _Integer __n, _Integer __x, __true_type) { _M_fill_insert(__pos, (size_type) __n, (value_type) __x); } template <class _InputIterator> void _M_insert_dispatch(iterator __pos, _InputIterator __first, _InputIterator __last, __false_type) { insert(__pos, __first, __last, __ITERATOR_CATEGORY(__first)); } #else /* __STL_MEMBER_TEMPLATES */ void insert(iterator __pos, const value_type* __first, const value_type* __last); void insert(iterator __pos, const_iterator __first, const_iterator __last); #endif /* __STL_MEMBER_TEMPLATES */ //改变容器大小 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; } iterator erase(iterator __first, iterator __last); void clear(); protected: // Internal construction/destruction void _M_fill_initialize(const value_type& __value); #ifdef __STL_MEMBER_TEMPLATES template <class _InputIterator> void _M_range_initialize(_InputIterator __first, _InputIterator __last, input_iterator_tag); template <class _ForwardIterator> void _M_range_initialize(_ForwardIterator __first, _ForwardIterator __last, forward_iterator_tag); #endif /* __STL_MEMBER_TEMPLATES */ protected: // Internal push_* and pop_* void _M_push_back_aux(const value_type&); void _M_push_back_aux(); void _M_push_front_aux(const value_type&); void _M_push_front_aux(); void _M_pop_back_aux(); void _M_pop_front_aux(); protected: // Internal insert functions #ifdef __STL_MEMBER_TEMPLATES template <class _InputIterator> void insert(iterator __pos, _InputIterator __first, _InputIterator __last, input_iterator_tag); template <class _ForwardIterator> void insert(iterator __pos, _ForwardIterator __first, _ForwardIterator __last, forward_iterator_tag); #endif /* __STL_MEMBER_TEMPLATES */ iterator _M_insert_aux(iterator __pos, const value_type& __x); iterator _M_insert_aux(iterator __pos); void _M_insert_aux(iterator __pos, size_type __n, const value_type& __x); #ifdef __STL_MEMBER_TEMPLATES template <class _ForwardIterator> void _M_insert_aux(iterator __pos, _ForwardIterator __first, _ForwardIterator __last, size_type __n); #else /* __STL_MEMBER_TEMPLATES */ void _M_insert_aux(iterator __pos, const value_type* __first, const value_type* __last, size_type __n); void _M_insert_aux(iterator __pos, const_iterator __first, const_iterator __last, size_type __n); #endif /* __STL_MEMBER_TEMPLATES */ iterator _M_reserve_elements_at_front(size_type __n) { size_type __vacancies = _M_start._M_cur - _M_start._M_first; if (__n > __vacancies) _M_new_elements_at_front(__n - __vacancies); return _M_start - difference_type(__n); } iterator _M_reserve_elements_at_back(size_type __n) { size_type __vacancies = (_M_finish._M_last - _M_finish._M_cur) - 1; if (__n > __vacancies) _M_new_elements_at_back(__n - __vacancies); return _M_finish + difference_type(__n); } void _M_new_elements_at_front(size_type __new_elements); void _M_new_elements_at_back(size_type __new_elements); protected: // Allocation of _M_map and nodes // Makes sure the _M_map has space for new nodes. Does not actually // add the nodes. Can invalidate _M_map pointers. (And consequently, // deque iterators.) void _M_reserve_map_at_back (size_type __nodes_to_add = 1) { //_M_map_size - (_M_finish._M_node - _M_map)表示map尾端节点的备用空间 if (__nodes_to_add + 1 > _M_map_size - (_M_finish._M_node - _M_map)) _M_reallocate_map(__nodes_to_add, false); } void _M_reserve_map_at_front (size_type __nodes_to_add = 1) { //_M_start._M_node - _M_map表示map头部节点的备用空间 if (__nodes_to_add > size_type(_M_start._M_node - _M_map)) _M_reallocate_map(__nodes_to_add, true); } void _M_reallocate_map(size_type __nodes_to_add, bool __add_at_front); };
- STL源码剖析 - 第4章 序列式容器 - deque
- 【STL源码剖析读书笔记】【第4章】序列式容器之deque
- 《STL源码剖析》 第4章 序列式容器总结
- STL源码剖析 - 第4章 序列式容器 - vector
- STL源码剖析 - 第4章 序列式容器 - list
- STL源码剖析 - 第4章 序列式容器 - stack
- STL源码剖析 - 第4章 序列式容器 - queue
- STL源码剖析 - 第4章 序列式容器 - heap
- STL源码剖析 - 第4章 序列式容器 - priority_queue
- STL源码剖析 - 第4章 序列式容器 - ilist
- STL源码剖析: 第4章 序列式容器
- STL源码剖析之序列容器deque
- STL源码剖析-序列式容器之deque
- STL源码剖析——序列容器之deque
- 《STL源码剖析》读书笔记---第4章 序列式容器
- 【STL源码剖析读书笔记】【第4章】序列式容器之vector
- 【STL源码剖析读书笔记】【第4章】序列式容器之list和slist
- 【STL源码剖析读书笔记】【第4章】序列式容器之stack和queue
- java测试httprequest(为手游开发后台数据传输做准备)
- jquery笔记
- ios-day10-05(ios项目中的常见文件。“工程名-Info.plist”文件、“工程名-Prefix.pch”文件)
- c# 获取网页源码
- 高性能、高并发TCP服务器(多线程调用libevent)
- STL源码剖析 - 第4章 序列式容器 - deque
- 小时转换为时间戳
- ios 模拟器中应用程序的存储路径
- Scramble String
- gdb调试手册
- 网络通信要注意的事
- 基于单文档程序的OCX创建方法:(OCXDoc的创建方法)
- NYOJ 737 石子合并(一)(区间动规)
- 在做自动化测试之前你需要知道的