1、deque概述
deque是一种双向开口的连续线性空间。所谓双向开口,意思是可以在头尾两端分别做元素的安插和删除动作,如图
vector 当然也可以在头尾两端做动作(从技术观点),但是其头部动作效率奇差,无法被接受。
没有所谓容量(capacity)观念,因为它是动态以分段连续空间组合而成,随时可以增加㆒段新的空间并链接起来。换句话说,像 vector 那样「因旧空间不足而重新配置一块更大空间,然后复制元素,再释放旧空间。这样的事情在 deque 是不会发生的。也因此,deque 没有必要提供所谓的空间保留(reserve)功能。deque允许在常数的时间内对起头端进行元素的安插或移除动作。
虽然 deque 也提供 Ramdon Access Iterator,但它的迭代器并不是原生指标,其复杂度和 vector 不可以道里计(稍后看到源码,你便知道),这当然在在影响了各个运算层面。因此,除非必要,我们应尽可能选择使用 vector 而非 deque。
2、deque中控器
inline size_t __deque_buf_size(size_t n, size_t sz)
{
return n != 0 ? n : (sz < 512 ? size_t(512 / sz) : size_t(1));
}
iterator start;
iterator finish;
map_pointer map; //指向map,map是连续空间,其内的每个元素都是一个指针,指向缓冲区
size_type map_size; //map内能容纳的节点数
3、deque迭代器
#ifndef __STL_NON_TYPE_TMPL_PARAM_BUG
template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator { //未继承std::iterator
typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
typedef __deque_iterator<T, const T&, const T*, BufSiz> const_iterator;
static size_t buffer_size() {return __deque_buf_size(BufSiz, sizeof(T)); }
//自己写5个必要的迭代器
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T** map_pointer;
typedef __deque_iterator self;
//与容器的联结
T* cur; //这个迭代器所指的缓存区的当前元素
T* first; //这个迭代器所指缓冲区的头元素
T* last; //这个迭代器所指缓冲区的尾部(含备用空间)
map_pointer node; //指向管控中心
//用map y来初始化迭代器
__deque_iterator(T* x, map_pointer y)
: cur(x), first(*y), last(*y + buffer_size()), node(y) {}
__deque_iterator() : cur(0), first(0), last(0), node(0) {} //默认构造函数
__deque_iterator(const iterator& x) //复制构造函数
: cur(x.cur), first(x.first), last(x.last), node(x.node) {}
reference operator*() const { return *cur; } //解引用
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
//重载减操作,两个迭代器的距离,先计算节点,然后加上位填满的区域
difference_type operator-(const self& x) const {
return difference_type(buffer_size()) * (node - x.node - 1) +
(cur - first) + (x.last - x.cur);
}
//自加,到了最后一个元素了,就要指向下一个缓冲区
self& operator++() {
++cur;
if (cur == last) {
set_node(node + 1);
cur = first;
}
return *this;
}
self operator++(int) {
self tmp = *this;
++*this;
return tmp;
}
//减操作,到达缓冲区的头了,就要指向前一个缓冲区
self& operator--() {
if (cur == first) {
set_node(node - 1);
cur = last;
}
--cur;
return *this;
}
self operator--(int) {
self tmp = *this;
--*this;
return tmp;
}
//随机存储,可以直接跳跃n个距离
self& operator+=(difference_type n) {
difference_type offset = n + (cur - first);
//还在一个缓冲区
if (offset >= 0 && offset < difference_type(buffer_size()))
cur += n;
else {
//已经不再同一个缓冲区了
difference_type node_offset =
offset > 0 ? offset / difference_type(buffer_size())
: -difference_type((-offset - 1) / buffer_size()) - 1;
//设置当前节点,到新的缓冲区
set_node(node + node_offset);
//当前指针也要移动到合适的位置
cur = first + (offset - node_offset * difference_type(buffer_size()));
}
return *this;
}
self operator+(difference_type n) const {
self tmp = *this;
return tmp += n;
}
self& operator-=(difference_type n) { return *this += -n; }
self operator-(difference_type n) const {
self tmp = *this;
return tmp -= n;
}
reference operator[](difference_type n) const { return *(*this + n); }
bool operator==(const self& x) const { return cur == x.cur; }
bool operator!=(const self& x) const { return !(*this == x); }
bool operator<(const self& x) const {
return (node == x.node) ? (cur < x.cur) : (node < x.node);
}
//设置节点,让这个迭代器指向新的map
void set_node(map_pointer new_node) {
node = new_node;
first = *new_node;
last = first + difference_type(buffer_size());
}
};
4、deque的数据结构
deque需要维护一个指向map的指针外,也要维护start和finish这两个迭代器,分别指向第一个缓冲区的第一个元素和最后一个缓冲区的最后一个元素。也要记住map的大小,如果map的节点不足,那么就要重新分配一个大一点的map.
template <class T, class Alloc = alloc, size_t BufSiz = 0>
class deque {
public: // Basic types
typedef T 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;
public: // Iterators
#ifndef __STL_NON_TYPE_TMPL_PARAM_BUG
typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
typedef __deque_iterator<T, const T&, const T&, BufSiz> const_iterator;
#else /* __STL_NON_TYPE_TMPL_PARAM_BUG */
typedef __deque_iterator<T, T&, T*> iterator;
typedef __deque_iterator<T, const T&, const T*> const_iterator;
#endif /* __STL_NON_TYPE_TMPL_PARAM_BUG */
#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: // Internal typedefs
typedef pointer* map_pointer;
typedef simple_alloc<value_type, Alloc> data_allocator;
typedef simple_alloc<pointer, Alloc> map_allocator;
static size_type buffer_size() {
return __deque_buf_size(BufSiz, sizeof(value_type));
}
static size_type initial_map_size() { return 8; }
protected: // Data members
iterator start; //第一个节点
iterator finish; //最后一个节点
map_pointer map; //指向map,map是一块连续的空间
size_type map_size; //map内的指标
public: // Basic accessors
iterator begin() { return start; }
iterator end() { return finish; }
const_iterator begin() const { return start; }
const_iterator end() const { return finish; }
reverse_iterator rbegin() { return reverse_iterator(finish); }
reverse_iterator rend() { return reverse_iterator(start); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(finish);
}
const_reverse_iterator rend() const {
return const_reverse_iterator(start);
}
reference operator[](size_type n) { return start[difference_type(n)]; }
const_reference operator[](size_type n) const {
return start[difference_type(n)];
}
reference front() { return *start; }
reference back() {
iterator tmp = finish;
--tmp;
return *tmp;
}
const_reference front() const { return *start; }
const_reference back() const {
const_iterator tmp = finish;
--tmp;
return *tmp;
}
size_type size() const { return finish - start;; }
size_type max_size() const { return size_type(-1); }
bool empty() const { return finish == start; }
//其他的省略
};
5、deque的建构与内存管理
deque定义了两个专属的空间配置器
//配置一个元素的大小
typedef simple_alloc<value_type, Alloc> data_allocator;
//配置一个指针的大小
typedef simple_alloc<pointer, Alloc> map_allocator;
构造函数
deque()
: start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(0);
}
deque(const deque& x)
: start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(x.size());
__STL_TRY {
uninitialized_copy(x.begin(), x.end(), start);
}
__STL_UNWIND(destroy_map_and_nodes());
}
deque(size_type n, const value_type& value)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value);
}
deque(int n, const value_type& value)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value);
}
deque(long n, const value_type& value)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value);
}
explicit deque(size_type n)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value_type());
}
deque(const value_type* first, const value_type* last)
: start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(last - first);
__STL_TRY {
uninitialized_copy(first, last, start);
}
__STL_UNWIND(destroy_map_and_nodes());
}
deque(const_iterator first, const_iterator last)
: start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(last - first);
__STL_TRY {
uninitialized_copy(first, last, start);
}
__STL_UNWIND(destroy_map_and_nodes());
}
//安排deque的结构
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::create_map_and_nodes(size_type num_elements) {
//需要的节点数目
size_type num_nodes = num_elements / buffer_size() + 1;
//map大小:最少为8,最多为所需节点+2
map_size = max(initial_map_size(), num_nodes + 2);
map = map_allocator::allocate(map_size);
//指向即诶但的中间位置,以保证能够很好的从尾部和首部插入
map_pointer nstart = map + (map_size - num_nodes) / 2;
map_pointer nfinish = nstart + num_nodes - 1;
map_pointer cur;
__STL_TRY {
//配置缓冲区
for (cur = nstart; cur <= nfinish; ++cur)
*cur = allocate_node();
}
//设置正确的的位置
start.set_node(nstart);
finish.set_node(nfinish);
start.cur = start.first;
finish.cur = finish.first + num_elements % buffer_size();
}
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::fill_initialize(size_type n,
const value_type& value) {
create_map_and_nodes(n);
map_pointer cur;
__STL_TRY {
for (cur = start.node; cur < finish.node; ++cur)
//为每一个节点设置初值
uninitialized_fill(*cur, *cur + buffer_size(), value);
//最后一个节点有备用空间,不用全部设置初值
uninitialized_fill(finish.first, finish.cur, value);
}
}
//从尾部压入
void push_back(const value_type& t) {
//还有足够的空间
if (finish.cur != finish.last - 1) {
construct(finish.cur, t);
++finish.cur;
}
else
//没有足够的空间
push_back_aux(t);
}
//从队列的首部压入
void push_front(const value_type& t) {
if (start.cur != start.first) {
construct(start.cur - 1, t);
--start.cur;
}
else
push_front_aux(t);
}
// Called only if finish.cur == finish.last - 1.
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::push_back_aux(const value_type& t) {
value_type t_copy = t;
reserve_map_at_back(); //符合某种条件需要换一个map
//配置新节点,然后构造
*(finish.node + 1) = allocate_node();
__STL_TRY {
construct(finish.cur, t_copy);
finish.set_node(finish.node + 1); //节点的位置要变了
finish.cur = finish.first;
}
__STL_UNWIND(deallocate_node(*(finish.node + 1)));
}
// Called only if start.cur == start.first.
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::push_front_aux(const value_type& t) {
value_type t_copy = t;
reserve_map_at_front();
*(start.node - 1) = allocate_node();
__STL_TRY {
start.set_node(start.node - 1);
start.cur = start.last - 1;
construct(start.cur, t_copy);
}
}
void reserve_map_at_back (size_type nodes_to_add = 1) {
//尾节点空间不足
if (nodes_to_add + 1 > map_size - (finish.node - map))
reallocate_map(nodes_to_add, false);//重新配置一个更大的map
}
void reserve_map_at_front (size_type nodes_to_add = 1) {
if (nodes_to_add > start.node - map)
reallocate_map(nodes_to_add, true);
}
void deque<T, Alloc, BufSize>::reallocate_map(size_type nodes_to_add,
bool add_at_front) {
size_type old_num_nodes = finish.node - start.node + 1;
size_type new_num_nodes = old_num_nodes + nodes_to_add;
map_pointer new_nstart;
if (map_size > 2 * new_num_nodes) {
new_nstart = map + (map_size - new_num_nodes) / 2
+ (add_at_front ? nodes_to_add : 0);
if (new_nstart < start.node)
copy(start.node, finish.node + 1, new_nstart);
else
copy_backward(start.node, finish.node + 1, new_nstart + old_num_nodes);
}
else {
size_type new_map_size = map_size + max(map_size, nodes_to_add) + 2;
//配置一块新的空间给map
map_pointer new_map = map_allocator::allocate(new_map_size);
new_nstart = new_map + (new_map_size - new_num_nodes) / 2
+ (add_at_front ? nodes_to_add : 0);
//把原来的map拷贝过来
copy(start.node, finish.node + 1, new_nstart);
map_allocator::deallocate(map, map_size);
//设定新map的起始位置
map = new_map;
map_size = new_map_size;
}
//重新设定迭代器start和finish
start.set_node(new_nstart);
finish.set_node(new_nstart + old_num_nodes - 1);
}
6、deque的元素操作
//弹出
void pop_back() {
if (finish.cur != finish.first) {
--finish.cur;
destroy(finish.cur);
}
else
pop_back_aux();
}
void pop_front() {
if (start.cur != start.last - 1) {
destroy(start.cur);
++start.cur;
}
else
pop_front_aux();
}
// Called only if finish.cur == finish.first.
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>:: pop_back_aux() {
//该缓冲区只有一个元素,
deallocate_node(finish.first);
finish.set_node(finish.node - 1);
finish.cur = finish.last - 1;
destroy(finish.cur);
}
// Called only if start.cur == start.last - 1. Note that if the deque
// has at least one element (a necessary precondition for this member
// function), and if start.cur == start.last, then the deque must have
// at least two nodes.
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::pop_front_aux() {
//该缓冲区只有一个元素
destroy(start.cur);
deallocate_node(start.first);
start.set_node(start.node + 1);
start.cur = start.first;
}
iterator erase(iterator pos) {
iterator next = pos;
++next;
//清除点之前的元素
difference_type index = pos - start;
//如果清楚点之前的元素比较少
if (index < (size() >> 1)) {//右移,相当于除以2
copy_backward(start, pos, next);//移动清除点前面的元素
pop_front(); //第一个元素去掉
}
else {//清除点后面的元素比较少
copy(next, finish, pos); //移动清除点后面的元素
pop_back(); //最后一个元素去掉
}
return start + index;
}