deque是一种双向开口的分段连续线性空间,可以在头尾端进行元素的插入和删除。
deque与vector最大的差异就是:
deque允许于常数时间内对头端进行插入或删除元素;
deque是分段连续线性空间,随时可以增加一段新的空间;deque不像vector那样,vector当内存不够时,需重新分配/复制数据/释放原始空间;
不过deque的迭代器设置比vector复杂,因为迭代器不能使用普通指针,因此尽量使用vector; 当对deque的元素进行排序时,为了提高效率,首先把deque数据复制到vector,利用vector的排序算法(利用STL的sort算法),排序之后再次复制回deque;
1:deque中控器
因为deque的空间是连续线性空间,所以需要一个中控器进行管理,deque对外的接口类似于连续空间,为了管理这些分段空间deque容器引进了map,和stl中的map,不是同一个概念,map是一小块连续的空间其中每个元素都是指向缓冲区的指针,缓冲区才是存储数据的主体
2:deque迭代器
deque是分段连续的线性空间,则普通指针不能作为deque的迭代器。迭代器设计时必须能够进行
operator++
或
operator--
操作,为了能够是用户随机访问容器,则必须对操作符进行重载。
deque迭代器的功能:
迭代器的数据结构如下:
deque迭代器的功能:
- 必须知道缓冲区的位置
- 能够判断是否处于其所在缓冲区的边界
- 能够知道其所在缓冲区当前所指位置的元素
- struct _Deque_iterator {
- ...
- //以下是迭代器设计的关键,访问容器的节点
- _Tp* _M_cur;//指向缓冲区当前的元素
- _Tp* _M_first;//指向缓冲区的头(起始地址)
- _Tp* _M_last;//指向缓冲区的尾(结束地址)
- _Map_pointer _M_node;//指向中控器的相应节点
- ...
- };
下面是迭代器的一些算法,同时是一些迭代器计算方法
//* 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;//指向最后一个节点
...
};
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;
}