deque是一个双向开口的容器,在头尾两端进行元素的插入跟删除操作都有理想的时间复杂度。
deque使用的是分段连续线性空间,它维护一个指针数组(T** map),其中每个指针指向一块连续线性空间。
(map左右两边一般留有剩余空间,用于前后插入元素,具体下面可以看到其实现)

根据上图,可以了解到deque的迭代器的基本定义。

1 template <class T, class Ref, class Ptr, size_t BufSiz>
2 struct __deque_iterator {
3 // 基本型别的定义
4 typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
5 typedef random_access_iterator_tag iterator_category;
6 typedef T value_type;
7 typedef Ptr pointer;
8 typedef Ref reference;
9 typedef size_t size_type;
10 typedef ptrdiff_t difference_type;
11 typedef T** map_pointer;
12 typedef __deque_iterator self;
13
14 // 缓冲区的大小
15 tatic size_t buffer_size() { ... }
16
17 // 主要维护的三个指针
18 T* cur; // 指向当前元素
19 T* first; // 指向当前缓冲区的头
20 T* last; // 指向当前缓冲区的尾
21
22 map_pointer node; // 指向当前缓冲区在map中的位置
23 // ...
24 };
deque的实现基本都是依赖于其迭代器的实现(主要是各种操作符的重载)

1 // 用于跳到下一个缓冲区
2 void set_node(map_pointer new_node) {
3 node = new_node;
4 first = *new_node;
5 last = first + difference_type(buffer_size());
6 }
7
8 reference operator*() const { return *cur; }
9 pointer operator->() const { return &(operator*()); }
10
11 self& operator++() {
12 ++cur;
13 if (cur == last) { // 到达缓冲区尾端
14 set_node(node + 1);
15 cur = first;
16 }
17 return *this;
18 }
19
20 self& operator--() {
21 if (cur == first) { // 已到达缓冲区头端
22 set_node(node - 1);
23 cur = last;
24 }
25 --cur;
26 return *this;
27 }
28
29 // 迭代器之间的距离(相隔多少个元素)
30 difference_type operator-(const self& x) const {
31 return difference_type(buffer_size()) * (node - x.node - 1) +
32 (cur - first) + (x.last - x.cur);
33 }
该迭代器还重载了operator+=、operator+、operator-=、operator-(difference_type)等,
都是通过set_node()跟调整cur、first、last、node成员来实现。同时重载的operator[]使用operator+来进行随机存取。

1 self& operator+=(difference_type n) {
2 difference_type offset = n + (cur - first);
3 if (offset >= 0 && offset < difference_type(buffer_size()))
4 cur += n;
5 else {
6 // 目标在不同的缓冲区
7 difference_type node_offset =
8 offset > 0 ? offset / difference_type(buffer_size())
9 : -difference_type((-offset - 1) / buffer_size()) - 1;
10 // 跳到相应的缓冲区
11 set_node(node + node_offset);
12 // 调整cur指针
13 cur = first + (offset - node_offset * difference_type(buffer_size()));
14 }
15 return *this;
16 }
17
18 // 下面的都直接或间接的调用operator+=
19 self operator+(difference_type n) const {
20 self tmp = *this;
21 return tmp += n;
22 }
23
24 self& operator-=(difference_type n) { return *this += -n; }
25
26 self operator-(difference_type n) const {
27 self tmp = *this;
28 return tmp -= n;
29 }
30
31 reference operator[](difference_type n) const { return *(*this + n); }
有了__deque_iterator,deque的基本实现就比较简单了(主要维护start、finish这两个迭代器)

下面是deque的基本定义

1 template <class T, class Alloc = alloc, size_t BufSiz = 0>
2 class deque {
3 public:
4 typedef T value_type;
5 typedef value_type* pointer;
6 typedef size_t size_type;
7 typedef pointer* map_pointer;
8 public:
9 typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
10 protected:
11 iterator start; // 第一个节点
12 iterator finish; // 最后一个结点
13
14 map_pointer map;
15 size_type map_size;
16 public:
17 iterator begin() { return start; }
18 iterator end() { return finish; }
19
20 reference operator[](size_type n) { return start[difference_type(n)]; } // 调用迭代器重载的operator[]
21
22 // ...
23 }
deque的constructor会调用create_map_and_nodes()来初始化map

1 // 每次配置一个元素大小的配置器
2 typedef simple_alloc<value_type, Alloc> data_allocator;
3 // 每次配置一个指针大小的配置器
4 typedef simple_alloc<pointer, Alloc> map_allocator;
5
6 template <class T, class Alloc, size_t BufSize>
7 void deque<T, Alloc, BufSize>::create_map_and_nodes(size_type num_elements) {
8 // 需要分配的结点数 如果为能整除 则多分配多一个结点
9 size_type num_nodes = num_elements / buffer_size() + 1;
10
11 // 分配结点内存 (前后预留一个 用于扩充)
12 map_size = max(initial_map_size(), num_nodes + 2);
13 map = map_allocator::allocate(map_size);
14
15 // 将需要分配缓冲区的结点放在map的中间
16 map_pointer nstart = map + (map_size - num_nodes) / 2;
17 map_pointer nfinish = nstart + num_nodes - 1;
18
19 map_pointer cur;
20 // 为了简化 去掉了异常处理的代码
21 for (cur = nstart; cur <= nfinish; ++cur)
22 *cur = allocate_node(); // 为每个结点分配缓冲区
23 }
24
25 // 设置start、finish指针
26 start.set_node(nstart);
27 finish.set_node(nfinish);
28 start.cur = start.first;
29 finish.cur = finish.first + num_elements % buffer_size();
30 }
下面就剩下插入跟删除元素的实现了,首先看看关于push_front()的操作的实现。

1 void push_front(const value_type& t) {
2 if (start.cur != start.first) { // 第一缓冲区还有容量
3 construct(start.cur - 1, t);
4 --start.cur;
5 }
6 else
7 push_front_aux(t);
8 }
9
10 // 如果第一缓冲区容量不足会调用这个函数来配置新的缓冲区
11 template <class T, class Alloc, size_t BufSize>
12 void deque<T, Alloc, BufSize>::push_front_aux(const value_type& t) {
13 value_type t_copy = t;
14 reserve_map_at_front(); // 可能导致map的重新整治
15 *(start.node - 1) = allocate_node();
16 start.set_node(start.node - 1);
17 start.cur = start.last - 1;
18 construct(start.cur, t_copy);
19 }
20
21 // 根据map前面为分配的结点数量来判断是否需要重新整治
22 void reserve_map_at_front (size_type nodes_to_add = 1) {
23 if (nodes_to_add > start.node - map)
24 reallocate_map(nodes_to_add, true);
25 }
上面留下的reallocate_map函数执行如下功能:
1.如果map中空闲指针足够多,则将已分配的结点移到map的中间。
2.否则重新分配一个map,将旧的map释放,把已分配的结点移到new_map的中间。
然后调整start跟finish迭代器。
然后是pop_front()的实现

1 void pop_front() {
2 if (start.cur != start.last - 1) {
3 destroy(start.cur);
4 ++start.cur;
5 }
6 else
7 pop_front_aux();
8 }
9
10 // 当前缓冲区只剩一个元素
11 template <class T, class Alloc, size_t BufSize>
12 void deque<T, Alloc, BufSize>::pop_front_aux() {
13 destroy(start.cur);
14 deallocate_node(start.first); // 释放该缓冲区
15 start.set_node(start.node + 1);
16 start.cur = start.first;
17 }
而push_back()跟pop_back()的实现跟上面的大同小异。
最后看看erase()跟insert()的实现

1 iterator erase(iterator pos) {
2 iterator next = pos;
3 ++next;
4 difference_type index = pos - start; // 迭代器的operator-
5 if (index < (size() >> 1)) { // 如果清除点之前的元素比较少
6 // 将清除点之前的所有元素后移一位 然后删除第一个元素
7 copy_backward(start, pos, next); // 利用了迭代器的operator--
8 pop_front();
9 }
10 else { // 如果清除点之后的元素比较少
11 // 将清除点之后的所有元素前移一位 然后删除最后一个元素
12 copy(next, finish, pos); // 利用了迭代器的operator++
13 pop_back();
14 }
15 return start + index;
16 }

1 iterator insert(iterator position, const value_type& x) {
2 if (position.cur == start.cur) {
3 // 插入位置为begin()
4 push_front(x);
5 return start;
6 }
7 else if (position.cur == finish.cur) {
8 // 插入位置为end()
9 push_back(x);
10 iterator tmp = finish;
11 --tmp;
12 return tmp;
13 }
14 else {
15 // 如果插入位置是在(begin(), end())
16 return insert_aux(position, x);
17 }
18 }
19
20 // insert_aux()跟erase()实现类似
21 // 调用copy()或者copy_backward()将元素前移或者后移
22 // 然后修改原来位置的值
来源:https://www.cnblogs.com/runnyu/p/6000368.html
