系列文章目录
C++ STL 序列式容器(一 vector, list)
deque
deque概述
vector是单向开口的连续线性空间,deque是一种双向开口的连续线性空间。和vector一样支持随机访问。 
<deque>成员函数接口
iterator erase(iterator pos);
iterator erase(iterator first, iterator last);
iterator insert(iterator position, const value_type& x);
deque的结构
deque的内部维护一个map,它本质是一个二级指针,解引用后得到一级指针,每个一级指针指向一块缓冲区(如图中所示),缓冲区用于存储deque的元素。
此外deque内部还维护两个迭代器start和finish,start迭代器用于维护第一缓冲区,finish用于维护最后缓冲区。
deque的迭代器内有四个数据成员:cur,first,last,node first指向缓冲区的头部,last指向缓冲区的尾后,它们都是一级指针,通过[first, last)可确定一个缓冲区; node指向map所指空间,所以node也是二级指针,对他解引用后得到指向缓冲区的指针; cur:(1)从迭代器的角度看,cur严格指向缓冲区的内部(cur != last),可以指示当前迭代器对象的状态,对迭代器解引用就是对cur解引用. (2)从deque的角度看,start.cur指向容器的首元素,finish.cur指向容器的尾后元素

iterator
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));
}
template<class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_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(BufSize, sizeof(T));
}
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;
...
void set_node(map_pointer new_node)
{
node = new_node;
first = *new_node;
last = first + difference_type(buffer_size());
}
reference operator*() const
{
return *cur;
}
pointer operator->() const
{
return &(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;
}
self& operator+=(difference_type n)
{
difference_type offset = cur + n - 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(ndoe + node_offset) ;
cur = first + (offset - node_offset*difference_type(buffer_size()));
}
return *this;
}
self& operator-=(difference_type n)
{
return operator+=(-n);
}
self operator+(difference_type n)
{
self tmp = *this;
tmp += n;
return tmp;
}
self operator-(difference_type n)
{
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!=(cosnt self& x) const
{
return !(*this == x);
}
bool operator<(cosnt self& x) const
{
return (node == x.node) ?
cur < x.cur :
node < x.node ;
}
};
deque 部分接口
//将pos位置于元素清除,后续元素向前移动,返回pos位置的元素指针
iterator erase(iterator pos);
//清除[first, last)位置的元素,返回first位置元素的指针
iterator erase(iterator first, iterator last);
//在元素*pos位置前方插入,返回pos位置的元素,即返回插入元素的迭代器
iterator insert(iterator position, const value_type& x);
主体结构
template<class T, class Alloc = alloc, size_t BufSiz = 0>
class deque
{
public:
typedef T value_type;
typedef value_type* pointer;
typedef size_t size_type;
public:
typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
protected:
typedef pointer* map_pointer;
protected:
iterator start;
iterator finish;
map_pointer map;
size_type map_size;
...
typedef simple_alloca<value_type, Alloc> data_allocator;
typedef simple_alloc<pointer, Alloc> map_allocator;
void fill_initialize(size_type n, const value_type& value);
void create_map_and_nodes(size_type);
void initial_map_size();
void allocate_node();
void push_back_aux(const value_type&);
void reserve_map_at_back();
void push_front_aux(const value_type&);
void reserve_map_at_front();
void reallocate_map(size_type);
void pop_back_aux();
void pop_front_aux();
iterator insert_aux(iteratpr, const value_type&);
public:
deque(int n, const value_type& value) :
start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value);
}
deque();
~deque();
public:
iterator begin()
{
return start;
}
iterator end()
{
return finish;
}
reference operator[](size_type n)
{
return *(start + n);
}
reference front()
{
return *start;
}
reference back()
{
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;
}
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) {
--start.cur;
construct(start.cur, t);
} else {
push_front_aux(t);
}
}
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();
}
}
void clear();
iterator erase(iterator pos);
iterator erase(iterator, iterator);
iterator insert(iterator, const value_type&);
};
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);
} catch (...) {
...
}
}
template<class T, class Alloc, size_t BufSiz>
void deque<T, Alloc, BufSiz>::create_map_and_nodes(size_type num_elements)
{
size_type num_nodes = num_elements / buffer_size() + 1;
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();
}
} catch (...) {
...
}
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 BufSiz>
void deque<T, Alloc, BufSiz>::push_back_aux(const value_type& t)
{
value_type t_copy = t;
reserve_map_at_back();
*(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) ) );
}
template<class T, class Alloc, size_t BufSiz>
void deque<T, Alloc, BufSiz>::push_front_aux(const value& 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);
} catch (...) {
start.set_node(start.node + 1);
start.cur = start.first;
deallocate_node(*(start.node - 1));
throw;
}
}
template<class T, class Alloc, size_t BufSiz>
void deque<T, Alloc, BufSiz>::reserve_map_at_back(size_type nodes_to_add = 1)
{
if (nodes_to_add > map_size - (finish.node - map + 1)){
reallocate_map(nodes_to_add, false);
}
}
template<class T, class Alloc, size_t BufSiz>
void deque<T, Alloc, BufSiz>::reserve_map_at_front(size_type nodes_to_add = 1)
{
if (nodes_to_add > start.node - map){
reallocate_map(nodes_to_add, true);
}
}
template<class T, class Alloc, size_t BufSiz>
void deque<T, Alloc, BufSiz>::reallocate_map(size_type nodes_to_add, bool add_to_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_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);
copy(start.node, finish.node + 1, new_start);
map_allocator::deallocatr(map, map_size);
map = new_map;
map_size = new_map_size;
}
start.set_node(new_nstart);
finish.set_node(new_nstart + old_num_nodes - 1);
}
template<class T, class Alloc, size_t BufSiz>
void deque<T, Alloc, BufSiz>::pop_back_aux()
{
deallocate_node(finish.first);
finish.set_node(finish.node - 1);
finish.cur = finish.last - 1;
destroy(finish.cur);
}
template<class T, class Alloc, size_t BufSiz>
void deque<T, Alloc, BufSiz>::pop_front_aux()
{
destroy(start.cur);
deallocate_node(first.first);
start.set_node(finish.node + 1);
start.cur = start.first;
}
template<class T, class Alloc, size_t BufSiz>
void deque<T, Alloc, BufSiz>::clear()
{
for (map_pointer node = first.ndoe+1; ndoe < finish.node; ++node){
destroy(*node, *node + buffer_size());
data_allocator::deallocate(*node, buffer_size());
}
if (start.ndoe != finish.node){
destroy(start.cur, start.last);
destroy(finish.first, finish.cur);
data_allocator::deallocate(finish.first, buffer_size());
} else {
destroy(start.cur, finish.cur);
}
finish = start;
}
template<class T, class Alloc, size_t BufSiz>
deque<T, Alloc, BufSiz>::iterator deque<T, Alloc, BufSiz>::erase(iterator pos)
{
iterator next = pos;
++next;
difference_type index = pos - start;
if (index < (size() >> 1)){
copy_backward(start, pos, next);
pop_front();
} else {
copy(next, finish, pos);
pop_back();
}
return start + index;
}
template<class T, class Alloc, size_t BufSiz>
deque<T, Alloc, BufSiz>::iterator
deque<T, Alloc, BufSiz>::erase(iterator first, iterator last)
{
if (first == start && last == finish){
clear();
return finish;
} else {
difference_type n = last - first;
difference_type elems_before = first - start;
if (elems_before < (size() - n) / 2){
copy_backward(start, first, last);
iterator new_start = start + n;
destroy(start, new_start);
for (map_pointer cur = start.node; cur < new_start.node; ++cur){
data_allocator::deallocate(*cur, buffer_size());
}
start = new_start;
}
else {
copy(last, finish, first);
iterator new_finish = finish - n;
destroy(new_finish, finish);
for (map_pointer cur = new_finish.node+1; cur<=finish.node; ++cur){
data_allocator::deallocate(*cur, buffer_size());
}
finish = new_finish;
}
return start + elems_before;
}
}
iterator insert(iterator position, const value_type& x)
{
if (position.cur == start.cur) {
push_front(x);
return start;
} else if (position == finish) {
push_back(x);
iterator tmp = finish;
--tmp;
return tmp;
} else {
return insert_aux(position, x);
}
}
template<class T, class Alloc, size_t BufSiz>
typename deque<T, Alloc, BufSiz>::iterator
deque<T, Alloc, BufSiz>::insert_aux(iterator pos, const value_type& x)
{
difference_type index = pos - start;
value_type x_copy = x;
if (index < size() / 2){
push_front(front());
iterator front1 = start;
++front1;
iterator front2 = front1;
++front2;
pos = start + index;
iterator pos1 = pos;
++pos1;
copy(front2, pos1, front1);
} else {
push_back(back());
iterator back1 = finish;
--back1;
iterator back2 = back1;
--back2;
pos = start + index;
copy_backward(pos, back2, back1);
}
*pos = x_copy();
return pos;
}
<stack>
stack 并非容器而是容器适配器,本质上就是把容器再进行包装 First In Last Out, FILO
stack标准操作为top, push, pop, size, empty 不支持随机访问
template<class T, class Sequence = deque<T>>
class stack
{
friend bool operator==__STL_NULL_TMPL_ARGS(const stack&, const stack&);
friend bool operator<__STL_NULL_TMPL_ARGS(const stack&, const stack&);
private:
friend bool operator==__STL_NULL_TMPL_ARGS(const stack&, const stack&);
friend bool operator<__STL_NULL_TMPL_ARGS(const stack&, const 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() const
{
return c.back();
}
void push(const value_type& x)
{
c.push_back(x);
}
void pop()
{
c.pop_back();
}
stack();
~stack();
};
template<class T, class Sequence>
bool operator==(const stack<T, Sequence>& x, const stack<T, Sequence>& y)
{
return x.c == y.c;
}
template<class T, class Sequence>
bool operator<(const stack<T, Sequence>& x, const stack<T, Sequence>& y)
{
return x.c < y.c;
}
<queue>
queue并非容器而是容器适配器,本质上就是把容器再进行包装 First In First Out, FIFO
queue标准操作为empty, size, front, back, push, pop 不支持随机访问
template<class T, class Sequence = deque<T>>
class queue
{
friend bool operator==__STL_NULL_TMPL_ARGS(const queue&, const queue&);
friend bool operator<__STL_NULL_TMPL_ARGS(const queue&, const 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();
}
queue();
~queue();
};
template<class T, class Sequence>
bool operator==(const queue<T, Sequence>&x,const queue<T, Sequence>&y)
{
return x.c == y.c;
}
template<class T, class Sequence>
bool operator<(const queue<T, Sequence>&x,const queue<T, Sequence>&y)
{
return x.c < y.c;
}
priority_queue 优先级队列
priority_queue内部的元素按照一定的优先级进行排列,本质上就是把容器再进行包装
提供的接口:empty, size, top, push, pop 不支持遍历也不支持随机访问
最后一个元素之前的满足堆条件,push_heap将最后的元素插入堆中,插入之后整个数组又都满足堆条件了。 ,整个数组满足堆条件,pop_heap将堆顶元素放到最后,此时该数组不满足堆条件,但最后一个元素之前的满足堆条件。
template<class T, class Sequence = vector<T>,
class Compare = less<typename Sequence::value_type> >
class priority_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;
Compare comp;
public:
priority_queue() : c() {}
explicit priority_queue(const Compare& x): c(), comp(x) {}
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last,const Compare& x)
:c(first, last), comp(x){ make_heap(c.begin(), c.end(), comp); }
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
: c(first, last) {make_heap(c.begin(), c.end(), comp); }
public:
bool empty() const
{
return c.empty();
}
size_type size() const
{
return c.size();
}
const_reference top() const
{
return c.front();
}
void push(const value_type& x)
{
__STL_TRY {
c.push_back(x);
push_heap(c.begin(), c.end(), comp);
}
__STL_UNWIND(c.clear());
}
void pop()
{
__STL_TRY {
pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
__STL_UNWIND(c.clear());
}
};
单向链表 slist
slist内部是一个单项链表,内部只有一个数据成员,为链表头部节点对象,head.next指向第一个元素所在的节点。
接口
begin, end, size, empty, front, push_front, pop_front, swap
迭代器

struct __slist_node_base
{
__slist_node_base* next;
};
template<class T>
struct __slist_node : public __slist_node_base
{
T data;
};
inline __slist_node_base* __slist_make_link(
__slist_node_base* prev_node,
__slist_node_base* new_node
)
{
new_node->next = prev_node->next;
prev_node->next = new_node;
return new_node;
}
inline size_t __slist_size(__slist_node_base* node)
{
size_t result = 0;
for (; node != 0; node = node->next){
++result;
}
return result;
}
struct __slist_iterator_base
{
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef forward_iterator_tag iterator_category;
__slist_node_base* node;
__slist_iterator_base(__slist_node_base* x): node(x) {}
void incr()
{
node = node->next;
}
bool operator==(const __slist_iterator_base& x) const
{
return node = x.node;
}
bool operator!=(const __slist_iterator_base& x) const
{
return node != x.node;
}
};
template<class T, class Ref, class Ptr>
struct __slist_iterator : public __slist_iterator_base
{
typedef __slist_iterator<T, T&, T*> iterator;
typedef __slist_iterator<T, const T&, const T*> const_iterator;
typedef __slist_iterator<R, Ref, Ptr> self;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __slist_node<T> list_node;
__slist_iterator(list_node* x) : __slist_iterator_base(x) {}
__slist_iterator() : __slist_iterator_base(0) {}
__slist_iterator(const iterator& x)
: __slist_iterator_base(x.node) {}
reference operator*() const
{
return ((list_node*) node)->data;
}
pointer operator->() const
{
return & (operator*());
}
self& operator++()
{
incr();
return *this;
}
self operator++(int)
{
self tmp = *this;
incr();
return tmp;
}
};
疑问?
为何该迭代器采用这种继承体系
slist 数据结构
template<class T, class Alloc = alloc>
class slist
{
public:
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;
typedef __slist_iterator<T, T&, T*> iterator;
typedef __slist_iterator<T, cosnt T&, const T*> const_iterator;
private:
typedef __slist_node<T> list_node;
typedef __slist_node_base list_node_base;
typedef __slist_iterator_base iterator_base;
typedef simple_alloc<list_node, Alloc> list_node_allocator;
static list_node* create_node(const value_type& x)
{
list_node* node = list_node_allocator::allocate();
__STL_TRY {
construct(&node->data, x);
node->next = 0;
}
__STL_UNWIND(list_node_allocator::deallocate(node));
return node;
}
static void destroy_node(list_node* node)
{
destroy(&node->data);
list_node_allocator::deallocate(node);
}
private:
list_node_base head;
public:
slist( ) { head.next = 0; }
~slist() { clear(); }
public:
iterator begin()
{
return iterator( (list_node*)head.next );
}
iterator end()
{
return iterator(0);
}
size_type size() const
{
return __slist_size(head.next);
}
bool empty() const
{
return head.next == 0;
}
void swap(slist& L)
{
list_node_base* tmp = head.next;
head.next = L.head.next;
L.head.next = tmp;
}
reference front()
{
return ((list_node*)head.next)->data;
}
void push_front(cosnt value_type& x)
{
__slist_make_link(&head, create_node(x));
}
void pop_front()
{
list_node* node = (list_node*) head.next;
head.next = node;
destroy_node(node);
}
...
};
总结
总结:
|