当前位置: 首页 > news >正文

C++初阶-queue和deque(队列和双端队列)

1.std::queue

在C++官网(链接:

Reference - C++ Referencehttps://legacy.cplusplus.com/reference)中,我们搜索queue有以下结果:

queue就是我们数据结构中的队列,关于队列,我在数据结构初阶中的博客讲解过,见:

数据结构初阶-队列-CSDN博客文章浏览阅读417次,点赞6次,收藏10次。概念:只允许在以一端进行插入数据的操作,只允许在另外一端进行删除数据的操作,其中插入数据的一端称为队尾,删除数据的一端称为队头,删除数据被称为出队列,插入数据称为入队列。所以我们可以称队列具有先入先出的特点,我们可以理解为我们去食堂等地方去排队时,先来的人先出去,而后来的人只能从最后进行往前走。但是我们需要的是结点的结构,所以这个结点包括:所存储的数据data,一个包含下一个结点的next指针。队列相对于之前的知识比较简单,下章将讲队列的应用,喜欢的可以一键三连(代码记得保存,下节课要用)。 https://blog.csdn.net/2401_86446710/article/details/145690769?spm=1011.2415.3001.10575&sharefrom=mp_manage_link队列就是先入先出的一个数据结构,只能在队尾入数据,只能在队头出数据,类似于我们生活中的排队一样,如果第一个人办完事情那么就出去,后面的人又往前一位的那样。

我只讲解一下每个函数的用处,每个函数的用法就不进行讲解了:

empty:队列判空;size:队列元素个数;front:返回队头元素;back:返回队尾元素;push:从队尾入队;emplace:和push功能差不多(具体要自行搜索资料,现阶段用得不多);pop:从队头出队;swap:交换两个队列;relational operators:各种操作符;swap(queue):交换两个队列。如果要交换q1和q2两个队列,我们可以:q1.swap(q2),也可以q2.swap(q1),还可以swap(q1,q2)。

2.std::deque

这个容器是C++新增的一个数据结构,可以认为是双端队列(两端开口即头、尾都可进行插入、删除的队列)。设计这个东西的目的是:满足在vector中中间插入、删除时效率很低,在list中不支持下标的随机访问,导致查找时效率很低。所以设计出来了一个新的数据结构deque,结合两个数据结构的优点创造出的一个新的数据结构。我们可以在C++官网中搜索deque有以下结果:

2.1std::deque的概述

我们把下面的解释用翻译器翻译一下得到了如下结果:

2.2std::deque的成员函数的概述

这些函数可以称之为:vector和list的结合,也就是说deque都可以用,其用法也不多讲了,只要知道有这个容器就可以了。

2.3std::deque的底层

deque(双端队列):是一种双开口的“连续”空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素,与list比较,空间利用率比较高(list要存储一个数据要存放prev指针、next指针,浪费空间比较多):

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个
动态的二维数组,其底层结构如下图所示:

双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问
的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:

那deque是如何借助其迭代器维护其假想连续的结构呢?

通过以上图片,我进行解释:如果在进行头插的时候,不是把原有元素往后移动一位,而是先看一下首元素前是否还有空间,如果有空间就直接插入,否则申请一块大小为buff(一个一维数组)的空间,然后从最后一个元素开始进行插入,其中还有中控台来存储这个buff的第一个元素和最后一个元素的地址,也就相当于:我们把链表中的一个结点扩展为一个一维数组了,而这个一维数组可以存放很多元素,而且每个元素的地址是连续的,也就是满足了下标的直接访问;如果用下标访问的方式来找数据,是从第一个buff数组开始看每个数组所存元素个数,然后依次减少,直到找到该下标为止的数据,比如:一个buff有10个数据,第一个buff只存了3个数据,我想访问第64个元素,我们先判断64是否小于3,如果不小于,那么就直接减;再依次比较每个buff的大小,重复操作之后找到即可,其实到第二个buff就可以直接取模操作得到那个buff数组的地址,再进行解引用即可。

如果我们想要在中间插入/删除数据,那么麻烦程度也是比较高的,首先我们需要判断:这个中间位置离开头近一些还是离结尾近一些,如果离开头近,那么把前面的所有数据进行往前/后移动,如果空间不够还需要扩容(只有插入时要判断),对于下标为1-9的(假设buff大小为10)(对于删除下标为0-9),直接赋值即可,但是对于下标为0/10的,则需要先找到前一个buff的最后一个元素的地址,然后进行赋值操作,如果数据量非常大,那么效率比vector还低一些,如果离结尾近,那么也差不多。

为什么中间插入/删除时不能直接在这个buff的前面和后面再申请一个buff数组大小的空间?

因为插入和删除操作本来就是很少见的,一般都是初始化的时候确定好空间大小了,所以如果就插入几次,那么再扩容一段有些大的空间(实际情况一个buff数组可能有1000个数据),那么就会很浪费空间,所以为了减少扩容,就只能用时间换空间了。

deque设计得非常复杂,所以我们要理解它是很麻烦的。

2.4std::deque的源码

这个源码是非常长的,如果不想看的话,可以直接跳转到2.5对于std::deque的源码的简单讲解。

std::deque的源码:

/*** Copyright (c) 1994* Hewlett-Packard Company** Permission to use, copy, modify, distribute and sell this software* and its documentation for any purpose is hereby granted without fee,* provided that the above copyright notice appear in all copies and* that both that copyright notice and this permission notice appear* in supporting documentation.  Hewlett-Packard Company makes no* representations about the suitability of this software for any* purpose.  It is provided "as is" without express or implied warranty.*** Copyright (c) 1997* Silicon Graphics Computer Systems, Inc.** Permission to use, copy, modify, distribute and sell this software* and its documentation for any purpose is hereby granted without fee,* provided that the above copyright notice appear in all copies and* that both that copyright notice and this permission notice appear* in supporting documentation.  Silicon Graphics makes no* representations about the suitability of this software for any* purpose.  It is provided "as is" without express or implied warranty.*//* NOTE: This is an internal header file, included by other STL headers.*   You should not attempt to use it directly.*/#ifndef __SGI_STL_INTERNAL_DEQUE_H
#define __SGI_STL_INTERNAL_DEQUE_H/* Class invariants:*  For any nonsingular iterator i:*    i.node is the address of an element in the map array.  The*      contents of i.node is a pointer to the beginning of a node.*    i.first == *(i.node) *    i.last  == i.first + node_size*    i.cur is a pointer in the range [i.first, i.last).  NOTE:*      the implication of this is that i.cur is always a dereferenceable*      pointer, even if i is a past-the-end iterator.*  Start and Finish are always nonsingular iterators.  NOTE: this means*    that an empty deque must have one node, and that a deque*    with N elements, where N is the buffer size, must have two nodes.*  For every node other than start.node and finish.node, every element*    in the node is an initialized object.  If start.node == finish.node,*    then [start.cur, finish.cur) are initialized objects, and*    the elements outside that range are uninitialized storage.  Otherwise,*    [start.cur, start.last) and [finish.first, finish.cur) are initialized*    objects, and [start.first, start.cur) and [finish.cur, finish.last)*    are uninitialized storage.*  [map, map + map_size) is a valid, non-empty range.  *  [start.node, finish.node] is a valid range contained within *    [map, map + map_size).  *  A pointer in the range [map, map + map_size) points to an allocated*    node if and only if the pointer is in the range [start.node, finish.node].*//** In previous versions of deque, node_size was fixed by the * implementation.  In this version, however, users can select* the node size.  Deque has three template parameters; the third,* a number of type size_t, is the number of elements per node.* If the third template parameter is 0 (which is the default), * then deque will use a default node size.** The only reason for using an alternate node size is if your application* requires a different performance tradeoff than the default.  If,* for example, your program contains many deques each of which contains* only a few elements, then you might want to save memory (possibly* by sacrificing some speed) by using smaller nodes.** Unfortunately, some compilers have trouble with non-type template * parameters; stl_config.h defines __STL_NON_TYPE_TMPL_PARAM_BUG if* that is the case.  If your compiler is one of them, then you will* not be able to use alternate node sizes; you will have to use the* default value.*/__STL_BEGIN_NAMESPACE #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma set woff 1174
#endif// Note: this function is simply a kludge to work around several compilers'
//  bugs in handling constant expressions.
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));
}#ifndef __STL_NON_TYPE_TMPL_PARAM_BUG
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(BufSiz, sizeof(T)); }
#else /* __STL_NON_TYPE_TMPL_PARAM_BUG */
template <class T, class Ref, class Ptr>
struct __deque_iterator {typedef __deque_iterator<T, T&, T*>             iterator;typedef __deque_iterator<T, const T&, const T*> const_iterator;static size_t buffer_size() {return __deque_buf_size(0, sizeof(T)); }
#endiftypedef 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;__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_OPERATORpointer 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;}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);}void set_node(map_pointer new_node) {node = new_node;first = *new_node;last = first + difference_type(buffer_size());}
};#ifndef __STL_CLASS_PARTIAL_SPECIALIZATION#ifndef __STL_NON_TYPE_TMPL_PARAM_BUGtemplate <class T, class Ref, class Ptr, size_t BufSiz>
inline random_access_iterator_tag
iterator_category(const __deque_iterator<T, Ref, Ptr, BufSiz>&) {return random_access_iterator_tag();
}template <class T, class Ref, class Ptr, size_t BufSiz>
inline T* value_type(const __deque_iterator<T, Ref, Ptr, BufSiz>&) {return 0;
}template <class T, class Ref, class Ptr, size_t BufSiz>
inline ptrdiff_t* distance_type(const __deque_iterator<T, Ref, Ptr, BufSiz>&) {return 0;
}#else /* __STL_NON_TYPE_TMPL_PARAM_BUG */template <class T, class Ref, class Ptr>
inline random_access_iterator_tag
iterator_category(const __deque_iterator<T, Ref, Ptr>&) {return random_access_iterator_tag();
}template <class T, class Ref, class Ptr>
inline T* value_type(const __deque_iterator<T, Ref, Ptr>&) { return 0; }template <class T, class Ref, class Ptr>
inline ptrdiff_t* distance_type(const __deque_iterator<T, Ref, Ptr>&) {return 0;
}#endif /* __STL_NON_TYPE_TMPL_PARAM_BUG */#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */// See __deque_buf_size().  The only reason that the default value is 0
//  is as a workaround for bugs in the way that some compilers handle
//  constant expressions.
template <class T, class Alloc = alloc, size_t BufSiz = 0> 
class deque {
public:                         // Basic typestypedef 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_BUGtypedef __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_SPECIALIZATIONtypedef 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 typedefstypedef 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 membersiterator start;iterator finish;map_pointer map;size_type map_size;public:                         // Basic accessorsiterator 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; }public:                         // Constructor, destructor.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());}#ifdef __STL_MEMBER_TEMPLATEStemplate <class InputIterator>deque(InputIterator first, InputIterator last): start(), finish(), map(0), map_size(0){range_initialize(first, last, iterator_category(first));}#else /* __STL_MEMBER_TEMPLATES */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());}#endif /* __STL_MEMBER_TEMPLATES */~deque() {destroy(start, finish);destroy_map_and_nodes();}deque& operator= (const deque& x) {const size_type len = size();if (&x != this) {if (len >= x.size())erase(copy(x.begin(), x.end(), start), finish);else {const_iterator mid = x.begin() + difference_type(len);copy(x.begin(), mid, start);insert(finish, mid, x.end());}}return *this;}        void swap(deque& x) {__STD::swap(start, x.start);__STD::swap(finish, x.finish);__STD::swap(map, x.map);__STD::swap(map_size, x.map_size);}public:                         // push_* and pop_*void push_back(const value_type& t) {if (finish.cur != finish.last - 1) {construct(finish.cur, t);++finish.cur;}elsepush_back_aux(t);}void push_front(const value_type& t) {if (start.cur != start.first) {construct(start.cur - 1, t);--start.cur;}elsepush_front_aux(t);}void pop_back() {if (finish.cur != finish.first) {--finish.cur;destroy(finish.cur);}elsepop_back_aux();}void pop_front() {if (start.cur != start.last - 1) {destroy(start.cur);++start.cur;}else pop_front_aux();}public:                         // Insertiterator insert(iterator position, const value_type& x) {if (position.cur == start.cur) {push_front(x);return start;}else if (position.cur == finish.cur) {push_back(x);iterator tmp = finish;--tmp;return tmp;}else {return insert_aux(position, x);}}iterator insert(iterator position) { return insert(position, value_type()); }void insert(iterator pos, size_type n, const value_type& x); void insert(iterator pos, int n, const value_type& x) {insert(pos, (size_type) n, x);}void insert(iterator pos, long n, const value_type& x) {insert(pos, (size_type) n, x);}#ifdef __STL_MEMBER_TEMPLATES  template <class InputIterator>void insert(iterator pos, InputIterator first, InputIterator last) {insert(pos, first, last, iterator_category(first));}#else /* __STL_MEMBER_TEMPLATES */void insert(iterator pos, const value_type* first, const value_type* last);void insert(iterator pos, const_iterator first, const_iterator last);#endif /* __STL_MEMBER_TEMPLATES */void resize(size_type new_size, const value_type& x) {const size_type len = size();if (new_size < len) erase(start + new_size, finish);elseinsert(finish, new_size - len, x);}void resize(size_type new_size) { resize(new_size, value_type()); }public:                         // Eraseiterator 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;}iterator erase(iterator first, iterator last);void clear(); protected:                        // Internal construction/destructionvoid create_map_and_nodes(size_type num_elements);void destroy_map_and_nodes();void fill_initialize(size_type n, const value_type& value);#ifdef __STL_MEMBER_TEMPLATES  template <class InputIterator>void range_initialize(InputIterator first, InputIterator last,input_iterator_tag);template <class ForwardIterator>void range_initialize(ForwardIterator first, ForwardIterator last,forward_iterator_tag);#endif /* __STL_MEMBER_TEMPLATES */protected:                        // Internal push_* and pop_*void push_back_aux(const value_type& t);void push_front_aux(const value_type& t);void pop_back_aux();void pop_front_aux();protected:                        // Internal insert functions#ifdef __STL_MEMBER_TEMPLATES  template <class InputIterator>void insert(iterator pos, InputIterator first, InputIterator last,input_iterator_tag);template <class ForwardIterator>void insert(iterator pos, ForwardIterator first, ForwardIterator last,forward_iterator_tag);#endif /* __STL_MEMBER_TEMPLATES */iterator insert_aux(iterator pos, const value_type& x);void insert_aux(iterator pos, size_type n, const value_type& x);#ifdef __STL_MEMBER_TEMPLATES  template <class ForwardIterator>void insert_aux(iterator pos, ForwardIterator first, ForwardIterator last,size_type n);#else /* __STL_MEMBER_TEMPLATES */void insert_aux(iterator pos,const value_type* first, const value_type* last,size_type n);void insert_aux(iterator pos, const_iterator first, const_iterator last,size_type n);#endif /* __STL_MEMBER_TEMPLATES */iterator reserve_elements_at_front(size_type n) {size_type vacancies = start.cur - start.first;if (n > vacancies) new_elements_at_front(n - vacancies);return start - difference_type(n);}iterator reserve_elements_at_back(size_type n) {size_type vacancies = (finish.last - finish.cur) - 1;if (n > vacancies)new_elements_at_back(n - vacancies);return finish + difference_type(n);}void new_elements_at_front(size_type new_elements);void new_elements_at_back(size_type new_elements);void destroy_nodes_at_front(iterator before_start);void destroy_nodes_at_back(iterator after_finish);protected:                      // Allocation of map and nodes// Makes sure the map has space for new nodes.  Does not actually//  add the nodes.  Can invalidate map pointers.  (And consequently, //  deque iterators.)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);}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 reallocate_map(size_type nodes_to_add, bool add_at_front);pointer allocate_node() { return data_allocator::allocate(buffer_size()); }void deallocate_node(pointer n) {data_allocator::deallocate(n, buffer_size());}#ifdef __STL_NON_TYPE_TMPL_PARAM_BUG
public:bool operator==(const deque<T, Alloc, 0>& x) const {return size() == x.size() && equal(begin(), end(), x.begin());}bool operator!=(const deque<T, Alloc, 0>& x) const {return size() != x.size() || !equal(begin(), end(), x.begin());}bool operator<(const deque<T, Alloc, 0>& x) const {return lexicographical_compare(begin(), end(), x.begin(), x.end());}
#endif /* __STL_NON_TYPE_TMPL_PARAM_BUG */
};// Non-inline member functionstemplate <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert(iterator pos,size_type n, const value_type& x) {if (pos.cur == start.cur) {iterator new_start = reserve_elements_at_front(n);uninitialized_fill(new_start, start, x);start = new_start;}else if (pos.cur == finish.cur) {iterator new_finish = reserve_elements_at_back(n);uninitialized_fill(finish, new_finish, x);finish = new_finish;}else insert_aux(pos, n, x);
}#ifndef __STL_MEMBER_TEMPLATES  template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert(iterator pos,const value_type* first,const value_type* last) {size_type n = last - first;if (pos.cur == start.cur) {iterator new_start = reserve_elements_at_front(n);__STL_TRY {uninitialized_copy(first, last, new_start);start = new_start;}__STL_UNWIND(destroy_nodes_at_front(new_start));}else if (pos.cur == finish.cur) {iterator new_finish = reserve_elements_at_back(n);__STL_TRY {uninitialized_copy(first, last, finish);finish = new_finish;}__STL_UNWIND(destroy_nodes_at_back(new_finish));}elseinsert_aux(pos, first, last, n);
}template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert(iterator pos,const_iterator first,const_iterator last)
{size_type n = last - first;if (pos.cur == start.cur) {iterator new_start = reserve_elements_at_front(n);__STL_TRY {uninitialized_copy(first, last, new_start);start = new_start;}__STL_UNWIND(destroy_nodes_at_front(new_start));}else if (pos.cur == finish.cur) {iterator new_finish = reserve_elements_at_back(n);__STL_TRY {uninitialized_copy(first, last, finish);finish = new_finish;}__STL_UNWIND(destroy_nodes_at_back(new_finish));}elseinsert_aux(pos, first, last, n);
}#endif /* __STL_MEMBER_TEMPLATES */template <class T, class Alloc, size_t BufSize>
deque<T, Alloc, BufSize>::iterator 
deque<T, Alloc, BufSize>::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;}
}template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::clear() {for (map_pointer node = start.node + 1; node < finish.node; ++node) {destroy(*node, *node + buffer_size());data_allocator::deallocate(*node, buffer_size());}if (start.node != finish.node) {destroy(start.cur, start.last);destroy(finish.first, finish.cur);data_allocator::deallocate(finish.first, buffer_size());}elsedestroy(start.cur, finish.cur);finish = start;
}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_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();}
#     ifdef  __STL_USE_EXCEPTIONS catch(...) {for (map_pointer n = nstart; n < cur; ++n)deallocate_node(*n);map_allocator::deallocate(map, map_size);throw;}
#     endif /* __STL_USE_EXCEPTIONS */start.set_node(nstart);finish.set_node(nfinish);start.cur = start.first;finish.cur = finish.first + num_elements % buffer_size();
}// This is only used as a cleanup function in catch clauses.
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::destroy_map_and_nodes() {for (map_pointer cur = start.node; cur <= finish.node; ++cur)deallocate_node(*cur);map_allocator::deallocate(map, map_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);}
#       ifdef __STL_USE_EXCEPTIONScatch(...) {for (map_pointer n = start.node; n < cur; ++n)destroy(*n, *n + buffer_size());destroy_map_and_nodes();throw;}
#       endif /* __STL_USE_EXCEPTIONS */
}#ifdef __STL_MEMBER_TEMPLATES  template <class T, class Alloc, size_t BufSize>
template <class InputIterator>
void deque<T, Alloc, BufSize>::range_initialize(InputIterator first,InputIterator last,input_iterator_tag) {create_map_and_nodes(0);for ( ; first != last; ++first)push_back(*first);
}template <class T, class Alloc, size_t BufSize>
template <class ForwardIterator>
void deque<T, Alloc, BufSize>::range_initialize(ForwardIterator first,ForwardIterator last,forward_iterator_tag) {size_type n = 0;distance(first, last, n);create_map_and_nodes(n);__STL_TRY {uninitialized_copy(first, last, start);}__STL_UNWIND(destroy_map_and_nodes());
}#endif /* __STL_MEMBER_TEMPLATES */// 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();*(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);}
#     ifdef __STL_USE_EXCEPTIONScatch(...) {start.set_node(start.node + 1);start.cur = start.first;deallocate_node(*(start.node - 1));throw;}
#     endif /* __STL_USE_EXCEPTIONS */
} // 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;
}      #ifdef __STL_MEMBER_TEMPLATES  template <class T, class Alloc, size_t BufSize>
template <class InputIterator>
void deque<T, Alloc, BufSize>::insert(iterator pos,InputIterator first, InputIterator last,input_iterator_tag) {copy(first, last, inserter(*this, pos));
}template <class T, class Alloc, size_t BufSize>
template <class ForwardIterator>
void deque<T, Alloc, BufSize>::insert(iterator pos,ForwardIterator first,ForwardIterator last,forward_iterator_tag) {size_type n = 0;distance(first, last, n);if (pos.cur == start.cur) {iterator new_start = reserve_elements_at_front(n);__STL_TRY {uninitialized_copy(first, last, new_start);start = new_start;}__STL_UNWIND(destroy_nodes_at_front(new_start));}else if (pos.cur == finish.cur) {iterator new_finish = reserve_elements_at_back(n);__STL_TRY {uninitialized_copy(first, last, finish);finish = new_finish;}__STL_UNWIND(destroy_nodes_at_back(new_finish));}elseinsert_aux(pos, first, last, n);
}#endif /* __STL_MEMBER_TEMPLATES */template <class T, class Alloc, size_t BufSize>
typename deque<T, Alloc, BufSize>::iterator
deque<T, Alloc, BufSize>::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;
}template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert_aux(iterator pos,size_type n, const value_type& x) {const difference_type elems_before = pos - start;size_type length = size();value_type x_copy = x;if (elems_before < length / 2) {iterator new_start = reserve_elements_at_front(n);iterator old_start = start;pos = start + elems_before;__STL_TRY {if (elems_before >= difference_type(n)) {iterator start_n = start + difference_type(n);uninitialized_copy(start, start_n, new_start);start = new_start;copy(start_n, pos, old_start);fill(pos - difference_type(n), pos, x_copy);}else {__uninitialized_copy_fill(start, pos, new_start, start, x_copy);start = new_start;fill(old_start, pos, x_copy);}}__STL_UNWIND(destroy_nodes_at_front(new_start));}else {iterator new_finish = reserve_elements_at_back(n);iterator old_finish = finish;const difference_type elems_after = difference_type(length) - elems_before;pos = finish - elems_after;__STL_TRY {if (elems_after > difference_type(n)) {iterator finish_n = finish - difference_type(n);uninitialized_copy(finish_n, finish, finish);finish = new_finish;copy_backward(pos, finish_n, old_finish);fill(pos, pos + difference_type(n), x_copy);}else {__uninitialized_fill_copy(finish, pos + difference_type(n),x_copy,pos, finish);finish = new_finish;fill(pos, old_finish, x_copy);}}__STL_UNWIND(destroy_nodes_at_back(new_finish));}
}#ifdef __STL_MEMBER_TEMPLATES  template <class T, class Alloc, size_t BufSize>
template <class ForwardIterator>
void deque<T, Alloc, BufSize>::insert_aux(iterator pos,ForwardIterator first,ForwardIterator last,size_type n)
{const difference_type elems_before = pos - start;size_type length = size();if (elems_before < length / 2) {iterator new_start = reserve_elements_at_front(n);iterator old_start = start;pos = start + elems_before;__STL_TRY {if (elems_before >= difference_type(n)) {iterator start_n = start + difference_type(n); uninitialized_copy(start, start_n, new_start);start = new_start;copy(start_n, pos, old_start);copy(first, last, pos - difference_type(n));}else {ForwardIterator mid = first;advance(mid, difference_type(n) - elems_before);__uninitialized_copy_copy(start, pos, first, mid, new_start);start = new_start;copy(mid, last, old_start);}}__STL_UNWIND(destroy_nodes_at_front(new_start));}else {iterator new_finish = reserve_elements_at_back(n);iterator old_finish = finish;const difference_type elems_after = difference_type(length) - elems_before;pos = finish - elems_after;__STL_TRY {if (elems_after > difference_type(n)) {iterator finish_n = finish - difference_type(n);uninitialized_copy(finish_n, finish, finish);finish = new_finish;copy_backward(pos, finish_n, old_finish);copy(first, last, pos);}else {ForwardIterator mid = first;advance(mid, elems_after);__uninitialized_copy_copy(mid, last, pos, finish, finish);finish = new_finish;copy(first, mid, pos);}}__STL_UNWIND(destroy_nodes_at_back(new_finish));}
}#else /* __STL_MEMBER_TEMPLATES */template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert_aux(iterator pos,const value_type* first,const value_type* last,size_type n)
{const difference_type elems_before = pos - start;size_type length = size();if (elems_before < length / 2) {iterator new_start = reserve_elements_at_front(n);iterator old_start = start;pos = start + elems_before;__STL_TRY {if (elems_before >= difference_type(n)) {iterator start_n = start + difference_type(n);uninitialized_copy(start, start_n, new_start);start = new_start;copy(start_n, pos, old_start);copy(first, last, pos - difference_type(n));}else {const value_type* mid = first + (difference_type(n) - elems_before);__uninitialized_copy_copy(start, pos, first, mid, new_start);start = new_start;copy(mid, last, old_start);}}__STL_UNWIND(destroy_nodes_at_front(new_start));}else {iterator new_finish = reserve_elements_at_back(n);iterator old_finish = finish;const difference_type elems_after = difference_type(length) - elems_before;pos = finish - elems_after;__STL_TRY {if (elems_after > difference_type(n)) {iterator finish_n = finish - difference_type(n);uninitialized_copy(finish_n, finish, finish);finish = new_finish;copy_backward(pos, finish_n, old_finish);copy(first, last, pos);}else {const value_type* mid = first + elems_after;__uninitialized_copy_copy(mid, last, pos, finish, finish);finish = new_finish;copy(first, mid, pos);}}__STL_UNWIND(destroy_nodes_at_back(new_finish));}
}template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert_aux(iterator pos,const_iterator first,const_iterator last,size_type n)
{const difference_type elems_before = pos - start;size_type length = size();if (elems_before < length / 2) {iterator new_start = reserve_elements_at_front(n);iterator old_start = start;pos = start + elems_before;__STL_TRY {if (elems_before >= n) {iterator start_n = start + n;uninitialized_copy(start, start_n, new_start);start = new_start;copy(start_n, pos, old_start);copy(first, last, pos - difference_type(n));}else {const_iterator mid = first + (n - elems_before);__uninitialized_copy_copy(start, pos, first, mid, new_start);start = new_start;copy(mid, last, old_start);}}__STL_UNWIND(destroy_nodes_at_front(new_start));}else {iterator new_finish = reserve_elements_at_back(n);iterator old_finish = finish;const difference_type elems_after = length - elems_before;pos = finish - elems_after;__STL_TRY {if (elems_after > n) {iterator finish_n = finish - difference_type(n);uninitialized_copy(finish_n, finish, finish);finish = new_finish;copy_backward(pos, finish_n, old_finish);copy(first, last, pos);}else {const_iterator mid = first + elems_after;__uninitialized_copy_copy(mid, last, pos, finish, finish);finish = new_finish;copy(first, mid, pos);}}__STL_UNWIND(destroy_nodes_at_back(new_finish));}
}#endif /* __STL_MEMBER_TEMPLATES */template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::new_elements_at_front(size_type new_elements) {size_type new_nodes = (new_elements + buffer_size() - 1) / buffer_size();reserve_map_at_front(new_nodes);size_type i;__STL_TRY {for (i = 1; i <= new_nodes; ++i)*(start.node - i) = allocate_node();}
#       ifdef __STL_USE_EXCEPTIONScatch(...) {for (size_type j = 1; j < i; ++j)deallocate_node(*(start.node - j));      throw;}
#       endif /* __STL_USE_EXCEPTIONS */
}template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::new_elements_at_back(size_type new_elements) {size_type new_nodes = (new_elements + buffer_size() - 1) / buffer_size();reserve_map_at_back(new_nodes);size_type i;__STL_TRY {for (i = 1; i <= new_nodes; ++i)*(finish.node + i) = allocate_node();}
#       ifdef __STL_USE_EXCEPTIONScatch(...) {for (size_type j = 1; j < i; ++j)deallocate_node(*(finish.node + j));      throw;}
#       endif /* __STL_USE_EXCEPTIONS */
}template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::destroy_nodes_at_front(iterator before_start) {for (map_pointer n = before_start.node; n < start.node; ++n)deallocate_node(*n);
}template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::destroy_nodes_at_back(iterator after_finish) {for (map_pointer n = after_finish.node; n > finish.node; --n)deallocate_node(*n);
}template <class T, class Alloc, size_t BufSize>
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);elsecopy_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_nstart);map_allocator::deallocate(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);
}// Nonmember functions.#ifndef __STL_NON_TYPE_TMPL_PARAM_BUGtemplate <class T, class Alloc, size_t BufSiz>
bool operator==(const deque<T, Alloc, BufSiz>& x,const deque<T, Alloc, BufSiz>& y) {return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
}template <class T, class Alloc, size_t BufSiz>
bool operator<(const deque<T, Alloc, BufSiz>& x,const deque<T, Alloc, BufSiz>& y) {return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}#endif /* __STL_NON_TYPE_TMPL_PARAM_BUG */#if defined(__STL_FUNCTION_TMPL_PARTIAL_ORDER) && \!defined(__STL_NON_TYPE_TMPL_PARAM_BUG)template <class T, class Alloc, size_t BufSiz>
inline void swap(deque<T, Alloc, BufSiz>& x, deque<T, Alloc, BufSiz>& y) {x.swap(y);
}#endif#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma reset woff 1174
#endif__STL_END_NAMESPACE #endif /* __SGI_STL_INTERNAL_DEQUE_H */// Local Variables:
// mode:C++
// End:

2.5对于std::deque的源码的简单讲解

这个源码非常长,有1335行,差不多30000个字,我们不需要看它太多部分,主要看它的类成员定义、operator++这些操作:

在97-100行、115-122行可以看到:

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(BufSiz, sizeof(T)); }
typedef T** map_pointer;typedef __deque_iterator self;T* cur;
T* first;
T* last;
map_pointer node;

可以知道node就是T**也就是我们的二维数组,这个数组里面还存放着开始位置的地址(first)、结束位置的地址(last),遍历到的位置的地址(cur),我们也就可以通过这些来进行操作。

在140-147行可以看到:

 self& operator++() {++cur;if (cur == last) {set_node(node + 1);cur = first;}return *this; }
//202-206行void set_node(map_pointer new_node) {node = new_node;first = *new_node;last = first + difference_type(buffer_size());}

这也就相当于如果遇到结尾就找下一个buff数组的地址这种操作。

在第252-261行、295-298行看到:

template <class T, class Alloc = alloc, size_t BufSiz = 0> 
class deque {
public:                         // Basic typestypedef 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;//295-298
protected:                      // Data membersiterator start;iterator finish;map_pointer map;size_type map_size;

其中的map代表我们的中控数组。

若只有一个buff那么map_size就为1,如果这个buff数组满了或者要头插而下标为0的位置的buff数组已经满了,那么就需要再申请一个buff数组的空间才行,这是finish的first指向该buff的开始,last指向该buff结束位置,cur也指向开始,node也指向开始,这样更方便控制遍历,也方便处理数据。若尾删,那么直接把最后一个buff数组空间释放掉,然后差不多的操作后把map_size--即可。

若头插,若第一个buff未满,则直接在cur位置插入,cur--;否则新申请一块空间,first指向开始,end指向结束位置,cur指向buff数组的结尾,node也指向结尾。

2.6对于std::deque的看法

deque有优点也有缺点,deque的优点:①头尾插入和删除效率很高,优于vector和list;②下标随机访问还行,略逊于vector(要有很多解引用等操作)。

deque的缺点:insert和erase的效率很长,若想效率高,最好:把该buff进行扩容(对进行操作的下标对应的那个buff),但是这会导致每个buff数据元素个数不一样,很难受,所以只能建议:减少使用insert/erase。

对于deque,它看似面面俱到,但效率差,也就是说它处处都不行,相当于对我们实际中的应用是一点用都没有的!

2.7std::deque的swap函数与std::vector的swap函数性能比较

用以下函数进行测试:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include<stdbool.h>
#include<stddef.h>//NULL
#include<time.h>
#include<iostream>
#include<deque>
#include<algorithm>
#include<vector>
using namespace std;
void test_op2()
{srand(time(0));const int N = 1000000;deque<int> dq1;deque<int> dq2;for (int i = 0; i < N; ++i){auto e = rand() + i;dq1.push_back(e);dq2.push_back(e);}int begin1 = clock();sort(dq1.begin(), dq1.end(), less<int>());int end1 = clock();int begin2 = clock();// 拷贝到vectorvector<int> v(dq2.begin(), dq2.end());sort(v.begin(), v.end());dq2.assign(v.begin(), v.end());int end2 = clock();printf("deque sort:%d\n", end1 - begin1);printf("deque copy vector sort, copy back deque:%d\n", end2 - begin2);
}int main()
{test_op2();return 0;
}

其实两个都是用库里面的swap函数进行特化出来的结果,基本上效率不会差多少,所以sort函数并写法差不多,所以更能体现二者的效率。

这是debug模式下的运行结果:

这是release版本下的运行结果:

可以看到,用vector的排序总比那个deque好多了,差不多是几倍左右,所以我们使用deque的地方是真的很少。

3.总结

queue和deque这两个容器都是用得不多的两个容器,除非我们要针对性写题目,这些才会用到,虽然deque确实功能丰富,但是它效率还是比较低的,所以建议不要用deque,我们可以在stack和queue中看到:

deque都作为它们的默认容器是因为本来这两个数据结构就可以有两种方式来实现,实践中建议用stack时第二个模板参数传递:vector<T>,用queue时建议第二个模板参数传递:list<T>,这样效率会高一些。

好了,这讲就到这里,喜欢的可以一键三连哦,下讲将讲解:priority_queue(优先级队列),不过下一讲可能要到7-3日考试完了之后了:

电路与电子学、离散数学、高等数学主播都没怎么学,所以需要一段时间的复习,英语听老师说这次难度比较高,所以为了防止挂科,没法更新,请各位谅解!

相关文章:

  • cockplit 出现 Cannot refresh cache whilst offline 处理
  • 时间序列分析
  • 【Java】抽象类与接口全解析
  • android 启动速度优化
  • Ubuntu 22.04离线安装Docker和NVIDIA Container Toolkit(使用gpu)
  • 在 VMware (WM) 虚拟机上安装的 Ubuntu 22.04 分配了 20GB 磁盘,但仅使用 10GB 就显示 “空间已满“
  • 【ZYNQ Linux开发】gpio子系统相关驱动先于Xgpio注册完成而加载失败的问题分析与探究
  • 《从IaaS到容器化:深度解析云计算三层架构与阿里云ECS+K8s协同实践》
  • 快速入门数据结构--栈
  • 【云计算领域数学基础】组合数学优化
  • 1.19集成开发环境(IDE)
  • 从loader和plugin开始了解webpack
  • Alova 封装与 Vue 3 集成示例
  • 大模型笔记3:通过插件增强大模型的能力
  • RabbitMQ消息队列实战指南
  • 【Go语言-Day 1】扬帆起航:从零到一,精通 Go 语言环境搭建与首个程序
  • qt信号与槽--02
  • SpringBoot电脑商城项目--项目分析及搭建
  • 2011-2020年各省互联网接入端口数数据
  • 项目实训个人工作梳理
  • 模仿别人的网站/百度指数的使用方法
  • 网站界面设计尺寸/广东短视频seo营销
  • 做汽车网站/免费推广方式都有哪些
  • css做电影海报网站设计/2022年新闻摘抄十条
  • 教育考试类网站建设/查域名
  • 网站在别人那里已经建好了_公司里要进行修改_怎么做/百度网址大全网站