Implementation of deque
- deque is a space with two-way openings, which is essentially piecewise continuous
- The specific implementation is shown in the figure below. First segment them, and then connect them in series. The bottom layer is a vector, which stores pointers to each buffer. The order of buffers is the same as that of vectors.
- The last buffer has been filled with elements. Allocate another buffer and connect it in series to the underlying vector to continue to expand backward. If the forward expanding buffer is also filled, allocate another buffer, and the empty position near the left element in the vector stores the pointer of the newly allocated buffer. When the control center is full, it will double its original capacity, similar to the dynamic growth of vector.
- deque's iterator is a class that has four elements.
- node points to the underlying vector, and when this iterator + + or -, it can jump to another buffer
- first points to the head of the current buffer and last points to the tail of the current buffer, both of which indicate the boundary of the buffer. If the pointer reaches the boundary of the current buffer, it will jump to the next buffer through the node pointer.
- cur is the element that the iterator currently points to (the function of the iterator is to point to an element)
- Almost all containers maintain two iterators, which point to the head and tail, start to start and end to finish

Version G2.9
- The iterator of deque has four pointers, with a size of 16. Deque has two iterators and two pointers, so the size is 40
- deque's iterators provide five related types
---------------------BufSize Calculation of------------------------
//If n is not 0, it means that the size of BufSize is user-defined, and N is returned
//If n is 0, it means that the size of BufSize uses the preset value
//If sz(sizeof(value_type)) is less than 512, 512/s is returned; If sz is not less than 512, 1 is returned
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));
}
---------------------deque Template class for--------------------
template<class T, class Alloc = alloc, size_t BufSize = 0>
class deque{
public:
typedef T value_type;
typedef __deque_iterator<T, T&, T*, BufSize> iterator;
protected:
typedef pointer* map_pointer;//T**
protected:
iterator start;
iterator finish;
map_pointer map;//Similar to a pointer to an array of pointers
size_type map_size;//Length of control center
public:
iterator begin() { return start; }//Returns the position of the first element
iterator end() { return finish; }//Returns the next position of the last element
size_type size() const { return finish - start;}
...
}
------------------------deque Iterator for----------------------
template<class T, class Ref, class Ptr, size_t BifSize>
struct __deque_iterator {
typedef random_access_iterator_tag iterator_category;//Random access iterators can use the + = operator
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;
...
}
----------------deque<T>::insert---------------------
//Insert an element at position with a value of x
//The insertion action will move the element, and the insert will determine whether the insertion position is closer to the front end or the back end, so as to obtain higher efficiency
iterator insert(iterator position, const value_type& x){
if(position.cur == start.cur){//If the front end of deque is inserted
push_front(x);//
return start;
} else if (position.cur == end.cur) {//If the insertion point is the tail end of deque
push_back(x);//Give it to push_back do
iterator tmp = finish;
--tmp;
return tmp;
}else {
return insert_aux(position, x);
}
}
//insert_aux
template<class T, class Alloc, size_t BufSize>
class deque<T, Alloc, BufSize>::iterator
deque<T, Alloc, BufSize>::insert_sux(iterator pos, const value_type& x){
difference_type index = pos - start;//Number of elements before insertion point
value_type x_copy = x;
if(index < size() / 2){//If the number of elements before the placement point is small
push_front(front());//Add an element with the same value as the first element at the front end
...
copy(front2, posl, front1);//Element movement
}
else{//The number of elements after the insertion point is small
push_back(back));//Add an element with the same value as the last element at the end
...
copy_backward(pos, back2, back1);//Element movement
}
*pos = x_copy;//Set the new value at the insertion point
return pos;
}
- How deque simulates continuous space
- ->Rely on iterators
- Member function of deque
reference operator[](size_type n)
{
return start[difference_type(n)];
}
reference front()//Returns the position of the first element
{ return *start; }
reference back()//Returns the position of the last element
{ //finish refers to the next position of the last element
iterator *tmp = finish;
--tmp;
return tmp;
}
size_type size() const//Returns the total number of elements
{ return finish - start; }//-Operator overloading
bool empty()
{ return finish == start; }

reference operator*() const
{ return *cur; }
pointer operator->() const
{ return &(operator*()); }
//Overloaded operators are generally used to calculate the distance between two iterators
//It is divided into three parts: the number of elements stored in the complete buffer, the number of elements in the end buffer and the number of elements in the starting buffer
difference_type
operator- (const self& x) const
{
return difference_type(buffer_size()) * (node - x.cur - 1) + (cur - first) + (x.last - x.cur);
}
- Operator overloading of iterators
//Modifying the position indicated by the iterator is a member function of the iterator
void set_node(map_pointer new_node)//Incoming modified location
{
node = new_node;//Modify the current location in the control center
first = *new_node;//Modify first to point to the new buffer
last = first + difference_type(buffer_size());//Modify last
}
self& operator++(){
++cur;//Switch to the next element
if( cur == last){//If it reaches the boundary, it jumps to the starting node of the next buffer
{
set_node(node + 1);
cur = first;
}
return *this;
}
self operator++(int)
{
selt tmp = *this;
++*this;
return tmp;
}
self& operator--()
{
if(cur == first){//If you are currently at the start node of the buffer, skip to the end of the previous buffer
set_node(node - 1);
cur = last;
}
--cur;
return *this;
}
self operator--(int)
{
self tmp = *this;
--*this;
return tmp;
}
self& operator+=(difference_type n){
difference_type offset = n + (cur - first);
if(offset >= 0 && offset < difference_type(buffer_size)))//The target location is within the same range
cur += n;
else{//The target location is no longer in the same range
//When the offset is negative, - 1 is calculated to reduce the classification discussion. In this way, when offset is equal to buffer_size, although the result of its division is 1, it falls into the category with quotient 0
difference_type node_offset = offset > 0 ? offset / difference_type(buffer_size) : - difference_type((-offset - 1) / buffer_size()) - 1;
//Switch to the correct buffer
set_node(node + node_offset);
//Switch to the correct element
cur = first + (offset - node_offset * difference_type(buffer_size()));
}
return *this;
}
self operator+ (difference_type n) const
{
self tmp = *this;
return tmp += n;
}
self& operstor-=(difference_type n)
{ return *this += -n; }
//There are two -- the first is to subtract the two iterators and find the distance between them. Here is to move the current iterator forward n positions
self operator-(difference_type n) const
{
self tmp = *this;
retturn tmp -= n;
}
reference operator[](difference_type n) const
{ return *(*this + n); }
Version G4.9

- The size of deque is 40
- deque's template parameters are changed to two, and the parameter to set the buffer size is cancelled
- The underlying implementation of deque's control center is vector, but it copies the elements to the middle of the vector every time it expands. In order to ensure that there are as many empty slots in the left and right parts as possible

queue
- queue can block some functions based on deque and become a new container
- queue doesn't need to define its own operations. It provides the ability to call the underlying deque container to complete the required operations
template<class T, class Sequence = deque<T>>
class queue{
...
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c;
public:
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference front() { return c.front(); }
const_reference front() const { return c.front(); }
reference back() { return c.back(); }
const_reference back() const { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_front(); }
};
stack
- stack contains a deque, which realizes the function by calling the interface of the underlying deque
template<class T, class Sequence = deque<T>>
class stack{
...
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c;
public:
bool empty() const{return c.empty(); }
size_type size() const { return c.size(); }
reference top() { return c.back(); }
const_reference top() { return c.back(); }
void push(const value_type& x) { c.push_back(x);}
void pop(){ c.pop_back); }
};
stack and queue
- Both list and deque can be used as their underlying structures
- stack and deque do not allow traversal, nor do they provide iterator s or insert s
- stack can select vector as the underlying container, but queue cannot select vector as the underlying container
- vector has no pop_front
- The compiler does not check the template comprehensively, and some functions will not be checked before use
- Neither stack nor queue can select set or map as the underlying container