STL(四) deque 双端队列

本文详细介绍了C++ STL中的双端队列(deque)数据结构。探讨了deque的底层实现原理,包括其独特的双向开口特性,内存分配策略以及迭代器架构。此外,还深入分析了deque的构造函数、成员函数、非成员函数等关键API,帮助读者全面掌握deque的使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

deque

底层数据结构

vector单向开口的线性连续空间deque则是一种双向开口连续数据空间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作。当然vector也可以在头尾两端进行操作,但是其头部操作效果奇差,所以标准库没有为vector提供push_front或pop_front操作。与vector类似,deque支持元素的快速随机访问。deque的示意图如下:

  现在问题来了:如果deque以数组来实现,如何做到在头部的常数时间插入?如果是采用链表来实现,又如何做到快速随机访问?deque的内部数据结构到底如何?想必你已经猜到了,要实现如上需求,需要由一段一段的连续空间链接起来的数据结构才能满足。

内存分配策略

接着上面讲。deque由一段一段的连续空间所链接而成,一旦需要在deque的前端或尾端增加新空间,便配置一段定量的连续空间,并将该空间串接在deque的头部或尾部。deque复杂的迭代器架构,构建出了所有分段连续空间”整体连续“的假象。
既然deque是由一段一段定长的连续空间所构成,就需要有结构来管理这些连续空间。deque采用一块map(非STL中的map)作为主控,map是一块小的连续空间,其中每个元素都是指针,指向一块较大的线性连续空间,称为缓冲区。而缓冲区才是存储deque元素的空间主体。示例图:

map本身也是一块固定大小的连续空间,当缓冲区数量增多,map容不下更多的指针时,deque会寻找一块新的空间来作为map。

deque的迭代器

为了使得这些分段的连续空间看起来像是一个整体,deque的迭代器必须有这样的能力:它必须能够指出分段连续空间在哪里,判断自己所指的位置s是否位于某一个缓冲区的边缘,如果位于边缘,则执行operator-- 或operator++时要能够自动跳到下一个缓冲区。因此,尽管deque的迭代器也是Ramdon Access Iterator 迭代器,但它的实现要比vector的复杂太多。SGI版本的STL deque实现思路可以看侯捷的《STL源码剖析》。

迭代器失效问题

  (1)在deque容器首部或者尾部插入元素不会使得任何迭代器失效。

  (2)在其首部或尾部删除元素则只会使指向被删除元素的迭代器失效。

  (3)在deque容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器失效。

deque使用优劣

   deque是在功能上合并了vector和list。

优点:(1) 随机访问方便,即支持[ ]操作符和vector.at()

         (2) 在内部方便的进行插入和删除操作

         (3) 可在两端进行push、pop

缺点:(1) 占用内存多

std::deque

template < class T, class Alloc = allocator<T> > class deque;

1、成员函数

构造 deque (公开成员函数)
explicit deque( const Allocator& alloc = Allocator() );
(C++14 前)
deque() : deque( Allocator() ) {}
explicit deque( const Allocator& alloc );
(C++14 起)
  (2) 
explicit deque( size_type count, 

                const T& value = T(),

                const Allocator& alloc = Allocator());
(C++11 前)
         deque( size_type count, 

                const T& value,

                const Allocator& alloc = Allocator());
(C++11 起)
  (3) 
explicit deque( size_type count );
(C++11 起) 
(C++14 前)
explicit deque( size_type count, const Allocator& alloc = Allocator() );
(C++14 起)
template< class InputIt >

deque( InputIt first, InputIt last, 

       const Allocator& alloc = Allocator() );
(4)  
deque( const deque& other );
(5)  
deque( const deque& other, const Allocator& alloc );
(5)(C++11 起)
deque( deque&& other );
(6)(C++11 起)
deque( deque&& other, const Allocator& alloc );
(7)(C++11 起)
deque( std::initializer_list<T> init, 
       const Allocator& alloc = Allocator() );
(8)(C++11 起)
   

从各种数据源构造新容器,可选地使用用户提供的分配器 alloc 。

1) 默认构造函数。构造空容器。
2) 构造拥有  count 个有值  value 的元素的容器。
3) 构造拥有个  count  默认插入的  T 实例的容器。不进行复制。
4) 构造拥有范围  [first, last) 内容的容器。
若 InputIt 是整数类型,则此构造函数拥有的效果同 deque(static_cast<size_type>(first)static_cast<value_type>(last), a) 。 (C++11 前)
此重载仅若InputIt 满足 输入迭代器 (InputIterator) 才参与重载决议,以避免和重载 (2) 的歧义。 (C++11 起)
5) 复制构造函数。构造拥有  other 内容的容器。若不提供  alloc ,则如同通过调用  std::allocator_traits<allocator_type>::select_on_container_copy_construction(other.get_allocator()) 获得分配器。
6) 移动构造函数。用移动语义构造拥有  other 内容的容器。分配器通过属于  other 的分配器移动构造获得。
7) 有分配器扩展的移动构造函数。将  alloc 用作新容器的分配器,从  other 移动内容;若  alloc != other.get_allocator() ,则它导致逐元素移动。
8) 构造拥有 initializer_list  init 内容的容器。

参数

alloc-用于此容器所有内存分配的分配器
count-容器的大小
value-以之初始化容器元素的值
first, last-复制元素的来源范围
other-用作初始化容器元素来源的另一容器
init-用作初始化元素来源的 initializer_list

复杂度

1) 常数
2-3) 与  count 成线性
4) 与  first 和  last 的距离成线性
5) 与  other 的大小成线性
6) 常数。
7) 若  alloc != other.get_allocator() 则为线性,否则为常数。
8) 与  init 的大小成线性。

异常

到 Allocator::allocate 的调用可能抛出。

注意

在容器移动构造(重载 (6) )后,指向 other 的引用及迭代器(除了尾迭代器)保持合法,但指代现于 *this 中的元素。




 
    
  
    
  
  
     
     
    
    
    
 

析构 deque 
(公开成员函数)
赋值给容器 (公开成员函数)
deque& operator=( const deque& other );
(1)  
  (2) 
deque& operator=( deque&& other );
 
deque& operator=( deque&& other ) noexcept(/* see below */);
 
deque& operator=( std::initializer_list<T> ilist );

替换容器内容。

1) 复制赋值运算符。以  other 的副本替换内容。 若 std::allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value 为 true ,则以源分配器的副本替换目标分配器。若源分配器与目标分配器不比较相等,则用目标( *this )分配器销毁内存,然后在复制元素前用 other 的分配器分配。 (C++11 起).、
2) 移动赋值运算符。用移动语义以  other 的内容替换内容(即从  other 移动  other 中的数据到此容器)。之后  other 在合法但未指定的状态。若  std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value 为  true ,则用源分配器的副本替换目标分配器。若它为  false 且源与目标分配器不比较相等,则目标不能取走源内存的所有权,而必须单独移动赋值逐个元素,用自己的分配器按需分配额外的内存。任何情况下,原先在  *this 中的元素要么被销毁,要么以逐元素移动赋值替换。
3) 以 initializer_list  ilist 所标识者替换内容。

参数

other-用作数据源的另一容器
ilist-用作数据源的 initializer_list

返回值

*this

复杂度

1) 与  *this 和  other 的大小成线性。
2) 与  *this 的大小成线性,除非分配器不比较相等且不传播,该情况下与  *this 和  other 的大小成线性。
3) 与  *this 和  ilist 的大小成线性。

异常

2) 
noexcept 规定:  
noexcept(std::allocator_traits<Allocator>::is_always_equal::value)
(C++17 起)

注意

容器移动赋值(重载 (2) )后,除非不兼容的分配器强制逐元素赋值,否则指向 other 的引用、指针和迭代器(除了尾迭代器)都保持合法,不过指代的元素现在在 *this 中。


将值赋给容器 (公开成员函数)
void assign( size_type count, const T& value );
(1)  
template< class InputIt >
void assign( InputIt first, InputIt last );
(2)  
void assign( std::initializer_list<T> ilist );
(3)(
   

替换容器的内容。

1) 以  count 份  value 的副本替换内容。
2) 以范围  [first, last) 中元素的副本替换内容
若 InputIt 为整数类型,则此重载与 (1) 拥有相同效果。  
此重载仅若 InputIt 满足输入迭代器 (InputIterator) 才参与重载决议。  
3) 以来自 initializer_list  ilist 的元素替换内容。

所有指向容器元素的迭代器、指针及引用均被非法化。尾后迭代器亦被非法化。

参数

count-容器的新大小
value-用以初始化容器元素的值
first, last-复制来源元素的范围
ilist-复制值来源的 initializer_list

复杂度

1) 与  count 成线性
2) 与  first 和  last 间的距离成线性
3) 与  ilist.size() 成线性

返回相关的分配器 (公开成员函数)
allocator_type get_allocator() const;
   
   

返回与容器关联的分配器。

参数

(无)

返回值

关联的分配器。

复杂度

常数。



#include<iostream>
#include<string>
#include<deque>

using namespace std;

//队列重载<<
template<typename T>
ostream& operator<<(ostream& s, const deque<T>& v)
{
	s.put('[');
	char comma[3] = { '\0', ' ', '\0' };
	for (const auto& e : v) {
		s << comma << e;
		comma[0] = ',';
	}
	return s << ']';
}

int main()
{
	deque<int>deq;
	deq.push_back(1);
	deq.push_back(2);
	deq.push_back(3);
	cout << "deq:" << deq << endl;

	deque<int>deq1(deq.begin(), deq.end());
	cout << "deq1:" << deq1 << endl;

	//复制构造
	deque<int>deq2(deq);
	cout << "deq2:" << deq2 << endl;

	deque<string>deq3(5, "AB");
	cout << "deq3:" << deq3 << endl;

	deque<int>num1{ 1, 2, 3, 4, 5, 6 };
	deque<int>num2;
	deque<int>num3;


	cout << "num1:" << num1 << endl;
	// 复制赋值会从 nums1 复制数据到 nums2
	num2 = num1;
	cout << "num2:" << num2 << endl;

	// 移动赋值会从 nums1 移动数据到 nums3 
	num3 = move(num2);
	cout << "num3:" << num3 << endl;

	deque<char>ch;
	ch.assign(6, '*');
	cout << "ch:" << ch << endl;

	//重新初始化对象
	num1.assign(2, 6);
	cout << "num1:" << num1 << endl;

	deque<char>ch1;
	ch1.assign(ch.begin(), ch.end());
	cout << "ch1:" << ch1 << endl;

	std::deque<int> mydeque;
	int * p;
	unsigned int i;

	//分配数组5个元素的空间用于deque分配器
	p = mydeque.get_allocator().allocate(5);

	// 空间中赋值
	for (i = 0; i<5; i++)
		mydeque.get_allocator().construct(&p[i], i);

	std::cout << "The allocated array contains:";
	for (i = 0; i<5; i++) std::cout << ' ' << p[i];
	std::cout << '\n';

	// 销毁空间
	for (i = 0; i<5; i++) mydeque.get_allocator().destroy(&p[i]);
	mydeque.get_allocator().deallocate(p, 5);




	system("pause");
	return 0;
}


2、

元素访问
at
访问指定的元素,同时进行越界检查 (公开成员函数)
reference       at( size_type pos );
   
const_reference at( size_type pos ) const;
   
   

返回位于指定位置 pos 的元素的引用,有边界检查。

若 pos 不在容器范围内,则抛出 std::out_of_range 类型的异常。

参数

pos-要返回的元素的位置

返回值

到所需元素的引用。

异常

若 !(pos < size()) 则抛出 std::out_of_range


访问指定的元素 (公开成员函数)
reference       operator[]( size_type pos );
   
const_reference operator[]( size_type pos ) const;
   
   

返回位于指定位置 pos 的元素的引用。不进行边界检查。

参数

pos-要返回的元素的位置

返回值

到所需元素的引用。

复杂度

常数。

注意

不同于 std::map::operator[] ,此运算符决不插入新元素到容器。


访问第一个元素 (公开成员函数)
reference front();
   
const_reference front() const;
   
   

返回到容器首元素的引用。

在空容器上对 front 的调用是未定义的。

参数

(无)

返回值

到首元素的引用

复杂度

常数

注意

对于容器 c ,表达式 c.front() 等价于 *c.begin() 。


访问最后一个元素 (公开成员函数)
reference back();
   
const_reference back() const;
   
   

返回到容器中最后一个元素的引用。

在空容器上对 back 的调用是未定义的。

参数

(无)

返回值

到最后元素的引用。

复杂度

常数。

注意

对于容器 c ,表达式 return c.back(); 等价于 { auto tmp = c.end(); --tmp; return *tmp; }



#include<iostream>
#include<string>
#include<deque>

using namespace std;

int main()
{
	deque<string>str;
	str.assign(2, "abac");
	str.push_back("aaa");
	str.push_back("bbb");
	str.push_back("ccc");
	cout << str.at(1) << endl;
	cout << str[3] << endl;
	cout << str.front() << endl;
	cout << str.back() << endl;

	system("pause");
	return 0;
}



3、

迭代器
返回指向容器第一个元素的迭代器 (公开成员函数)
iterator begin();
 (C++11 前)
iterator begin() noexcept;
 (C++11 起)
const_iterator begin() const;
 (C++11 前)
const_iterator begin() const noexcept;
 (C++11 起)
const_iterator cbegin() const noexcept;
 (C++11 起)
   

返回指向容器首元素的迭代器。

若容器为空,则返回的迭代将等于 end() 。

range-begin-end.svg

参数

(无)

返回值

指向首元素的迭代器

复杂度

常数


返回指向容器尾端的迭代器 (公开成员函数)
iterator end();
 (C++11 前)
iterator end() noexcept;
 (C++11 起)
const_iterator end() const;
 (C++11 前)
const_iterator end() const noexcept;
 (C++11 起)
const_iterator cend() const noexcept;
 (C++11 起)
   

返回指向后随容器最后元素的元素的迭代器。

此元素表现为占位符;试图访问它导致未定义行为。

range-begin-end.svg

参数

(无)

返回值

指向后随最后元素的迭代器。

复杂度

常数。


返回一个指向容器最后一个元素的反向迭代器 (公开成员函数)
reverse_iterator rbegin();
 (C++11 前)
reverse_iterator rbegin() noexcept;
 (C++11 起)
const_reverse_iterator rbegin() const;
 (C++11 前)
const_reverse_iterator rbegin() const noexcept;
 (C++11 起)
const_reverse_iterator crbegin() const noexcept;
 (C++11 起)
   

返回值指向逆向容器的首元素。它对应非逆向容器的最末元素。

range-rbegin-rend.svg

参数

(无)

返回值

指向首元素的逆向迭代器。

复杂度

常数


返回一个指向容器前端的反向迭代器 (公开成员函数)
reverse_iterator rend();
 (C++11 前)
reverse_iterator rend() noexcept;
 (C++11 起)
const_reverse_iterator rend() const;
 (C++11 前)
const_reverse_iterator rend() const noexcept;
 (C++11 起)
const_reverse_iterator crend() const noexcept;
 (C++11 起)
   

返回逆向容器末元素的后一元素。它对应非逆向容器首元素的前一元素。此元素表现为占位符,试图访问它导致未定义行为。

range-rbegin-rend.svg

参数

(无)

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。



#include<iostream>
#include<string>
#include<deque>

using namespace std;

int main()
{
	deque<string>str;
	str.assign(2, "abac");
	str.push_back("aaa");
	str.push_back("bbb");
	str.push_back("ccc");

	//迭代器
	deque<string>::iterator iter = str.begin();
	for (; iter != str.end();)
	{
		cout << *iter++ << ' ';
	}
	cout << endl;

	//常迭代器
	deque<string>::const_iterator iter1 = str.begin();
	for (; iter1 != str.end();)
	{
		cout << *iter1++ << ' ';
	}
	cout << endl;

	//常反迭代器
	deque<string>::const_reverse_iterator iter2 = str.rbegin();
	for (; iter2 != str.rend();)
	{
		cout << *iter2++ << ' ';
	}
	cout << endl;

	system("pause");
	return 0;
}



4、

容量
检查容器是否为空 (公开成员函数)
bool empty() const;
 (C++11 前)
bool empty() const noexcept;
 (C++11 起) 
(C++20 前)
[[nodiscard]] bool empty() const noexcept;
 (C++20 起)
   

检查容器是否无元素,即是否 begin() == end() 。

参数

(无)

返回值

若容器为空则为 true ,否则为 false

复杂度

常数。


返回容纳的元素数 (公开成员函数)
size_type size() const;
 (C++11 前)
size_type size() const noexcept;
 (C++11 起)
   

返回容器中的元素数,即 std::distance(begin(), end()) 。

参数

(无)

返回值

容器中的元素数量。

复杂度

常数。


返回可容纳的最大元素数 (公开成员函数)
size_type max_size() const;
 (C++11 前)
size_type max_size() const noexcept;
 (C++11 起)
   

返回根据系统或库实现限制的容器可保有的元素最大数量,即对于最大容器的 std::distance(begin(), end()) 。

参数

(无)

返回值

元素数量的最大值。

复杂度

常数。

注意

此值典型地反映容器大小上的理论极限。运行时,容器的大小可能被可用 RAM 总量限制到小于 max_size() 的值。


(C++11)
通过释放未使用的内存减少内存的使用 (公开成员函数)
void shrink_to_fit();
 (C++11 起)
   

请求移除未使用的容量。

它是减少使用内存而不更改序列的大小非强制性请求。请求是否达成依赖于实现。

所有迭代器和引用都被非法化。尾后迭代器亦被非法化。

参数

(无)

类型要求
-
T 必须满足 MoveInsertable 的要求。

返回值

(无)

复杂度

至多与容器大小成线性。

注意

若 T 移动构造函数以外的操作抛出异常,则无效果。



#include<iostream>
#include<string>
#include<deque>
#include<ctime>
using namespace std;

int main()
{
	srand(time(0));
	deque<char> ch;
	for (int i = 0; i < 10; i++)
		ch.push_back((char)rand() % 10);

	cout << "ch size:" << ch.size() << endl;
	if (ch.empty() == 0)
		cout << "ch is null" << endl;

	ch.resize(20);
	//容器可保有的元素最大数量
	cout << "ch max_size:" << ch.max_size() << endl;

	// 调用 shrink_to_fit 可能会释放任何不使用的内存。
	ch.shrink_to_fit();
	cout << "ch size:" << ch.size() << endl;



	system("pause");
	return 0;
}








5、

修改器
清除内容 (公开成员函数)
void clear();
 (C++11 前)
void clear() noexcept;
 (C++11 起)
   

从容器移除所有元素。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器亦被非法化。

参数

(无)

返回值

(无)

复杂度

与容器大小,即元素数成线性。


插入元素 (公开成员函数)
iterator insert( iterator pos, const T& value );
(C++11 前)
iterator insert( const_iterator pos, const T& value );
(C++11 起)
iterator insert( const_iterator pos, T&& value );
(2)(C++11 起)
  (3) 
void insert( iterator pos, size_type count, const T& value );
(C++11 前)
iterator insert( const_iterator pos, size_type count, const T& value );
(C++11 起)
  (4) 
template< class InputIt >
void insert( iterator pos, InputIt first, InputIt last);
(C++11 前)
template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last );
(C++11 起)
iterator insert( const_iterator pos, std::initializer_list<T> ilist );
(5)(C++11 起)
   

插入元素到容器中的指定位置。

1-2) 在  pos 前插入  value 。
3) 在  pos 前插入  value 的  count 个副本。
4) 在  pos 前插入来自范围  [first, last) 的元素。
若 InputIt 为整数类型,则此重载与重载 (3) 拥有相同效果。 (C++11 前)
此重载仅若 InputIt 足以为输入迭代器 (InputIterator) 才参与重载决议,以避免与重载 (3) 有歧义。 (C++11 起)
若  first 和  last 是指向  *this 中的迭代器,则行为未定义。
5) 在  pos 前插入来自 initializer_list  ilist 的元素。

所有迭代器,含尾后迭代器,都被非法化。引用亦被非法化,除非 pos == begin() 或 pos == end() ,该情况下它们不被非法化。

参数

pos-将内容插入到其前的迭代器。 pos 可为 end() 迭代器
value-要插入的元素值
first, last-要插入的元素范围,不能是指向调用 insert 所用的容器中的迭代器
ilist-要插入的值来源的 initializer_list
类型要求
-
 为使用重载 (1) , T 必须满足 CopyAssignable 和 CopyInsertable 的要求。
-
 为使用重载 (2) , T 必须满足 MoveAssignable 和 MoveInsertable 的要求。
-
 为使用重载 (3) , T 必须满足 CopyAssignable 和 CopyInsertable 的要求。
-
 为使用重载 (4,5) , T 必须满足 EmplaceConstructible 的要求。
-
 为使用重载 (4,5) , T 必须满足 Swappable 、 MoveAssignable 、 MoveConstructible 和 MoveInsertable 的要求。(C++17 起)

返回值

1-2) 指向被插入  value 的迭代器。
3) 指向首个被插入元素的迭代器,或若  count==0 则为  pos 。
4) 指向首个被插入元素的迭代器,或若  first==last 则为  pos 。
5) 指向首个被插入元素的迭代器,或若  ilist 为空则为  pos 。

复杂度

1-2) 常数,加上与  pos 和容器两端距离的较小者成线性。
3) 与  count 成线性,加上与  pos 和容器两端距离的较小者成线性。
4) 与  std::distance(first, last) 成线性,加上与  pos 和容器两端距离的较小者成线性。
5) 与  ilist.size() 成线性,加上与  pos 和容器两端距离的较小者成线性。

异常

若在任一端插入单个元素时抛出异常,则此函数无效果(强异常保证)。


(C++11)
原位构造元素 (公开成员函数)
template< class... Args > 
iterator emplace( const_iterator pos, Args&&... args );
 (C++11 起)
   

直接于 pos 前插入元素到容器中。通过 std::allocator_traits::construct 构造元素,它典型地用布置 new 在容器所提供的位置原位构造元素。将参数 args... 作为 std::forward<Args>(args)... 转发给构造函数。

所有迭代器,含尾后迭代器,都被非法化。引用亦被非法化,除非 pos == begin() 或 pos == end() ,该情况下它们不被非法化。

参数

pos-将构造新元素到其前的迭代器
args-转发给元素构造函数的参数
类型要求
-
T (容器元素类型) 必须满足 MoveAssignable 、 MoveInsertable 和 EmplaceConstructible 的要求。

返回值

指向被安置的元素的迭代器。

复杂度

与 pos 和容器两端距离的较小者成线性。

异常

若 value_type 的复制构造函数、移动构造函数、赋值运算符或移动赋值运算符以外的操作抛异常,或若在用 emplace 在任一端插入单个元素时抛异常,则无效果(强异常保证)。

否则,效果未指定。


擦除元素 (公开成员函数)
iterator erase( iterator pos );
(C++11 前)
iterator erase( const_iterator pos );
(C++11 起)
  (2) 
iterator erase( iterator first, iterator last );
(C++11 前)
iterator erase( const_iterator first, const_iterator last );
(C++11 起)
   

从容器移除指定的元素。

1) 移除位于  pos 的元素。
2) 移除范围  [first; last) 中的元素。

所有迭代器和引用都被非法化,除非被擦除的元素在容器的首或尾,该情况下仅指向被擦除元素的迭代器或引用被非法化。

尾后迭代器是否被非法化是未指定的。 (C++11 前)
尾后迭代器亦被非法化,除非被擦除元素在容器首,而尾元素未被擦除。 (C++11 起)

迭代器 pos 必须合法且可解引用。从而不能以 end() 迭代器(合法,但不可解引用)为 pos 的值。

若 first==last 则迭代器 first 不必可解引用:擦除空范围是无操作。

参数

pos-指向要移除的元素的迭代器
first, last-要移除的元素范围
类型要求
-
T 必须满足 MoveAssignable 的要求。

返回值

后随最后被移除元素的迭代器。若迭代器 pos 指代最后元素,则返回 end() 迭代器。

异常

不抛出,除非 T 的赋值运算符抛异常。

复杂度

线性:调用 T 析构函数的次数与被擦除的元素数相同,调用 T 赋值运算符的次数不多于被擦除元素前的元素数和被擦除元素后的元素数。


将元素添加到容器末尾 (公开成员函数)
void push_back( const T& value );
(1)  
void push_back( T&& value );
(2)(C++11 起)
   

后附给定元素 value 到容器尾。

1) 初始化新元素为  value 的副本。
2) 移动  value 进新元素。

所有迭代器,包含尾后迭代器,都被非法化。没有引用被非法化。

参数

value-要后附的元素值
类型要求
-
 为使用重载 (1) , T 必须满足 CopyInsertable 的要求。
-
 为使用重载 (2) , T 必须满足 MoveInsertable 的要求。

返回值

(无)

复杂度

常数。

异常

若抛出异常(可能因为 Allocator::allocate() 或元素复制/移动构造函数/赋值),则此函数无效果(强异常保证)。



(C++11)
在容器末尾就地构造元素 (公开成员函数)
template< class... Args >
void emplace_back( Args&&... args );
 (C++11 起) 
(C++17 前)
template< class... Args >
reference emplace_back( Args&&... args );
 (C++17 起)
   

添加新元素到容器尾。元素通过 std::allocator_traits::construct 构造,它典型地用布置 new 于容器所提供的位置原位构造元素。参数 args... 以 std::forward<Args>(args)... 转发到构造函数。

所有迭代器,包含尾后迭代器,都被非法化。没有引用被非法化。

参数

args-转发到元素构造函数的参数
类型要求
-
T (容器元素类型) 必须满足 EmplaceConstructible 的要求。

返回值

(无) (C++17 前)
到被插入元素的引用。 (C++17 起)

复杂度

常数。

异常

若抛出异常,则此函数无效果(强异常保证)。


移除末元素 (公开成员函数)
void pop_back();
   
   

移除容器的最末元素。

在空容器上调用 pop_back 是未定义的。

指向被擦除元素的迭代器和引用被非法化。尾后迭代器是否被非法化是未指定的。其他迭代器和引用不受影响。 (C++11 前)
指向被擦除元素的迭代器和引用被非法化。尾后迭代器亦被非法化。其他引用和迭代器不受影响。 (C++11 起)

参数

(无)

返回值

(无)

复杂度

常数。

异常

(无)


插入元素到容器起始 (公开成员函数)
void push_front( const T& value );
   
void push_front( T&& value );
 (C++11 起)
   

前附给定元素 value 到容器起始。

所有迭代器,包含尾后迭代器,都被非法化。没有引用被非法化。

参数

value-要前附的元素值

返回值

(无)

复杂度

常数。

异常

若抛出异常,则此函数无效果(强异常保证)。


(C++11)
在容器头部就地构造元素 (公开成员函数)
template< class... Args >
void emplace_front( Args&&... args );
 (C++11 起) 
(C++17 前)
template< class... Args >
reference emplace_front( Args&&... args );
 (C++17 起)
   

插入新元素到容器起始。通过 std::allocator_traits::construct 构造元素,它典型地用布置 new 在容器所提供的位置原位构造元素。将参数 args... 作为 std::forward<Args>(args)... 转发给构造函数。

所有迭代器,包含尾后迭代器,都被非法化。没有引用被非法化。

参数

args-转发给元素构造函数的参数
类型要求
-
T (容器元素类型) 必须满足 EmplaceConstructible 的要求。

返回值

(无) (C++17 前)
到被插入元素的引用。 (C++17 起)

复杂度

常数。

异常

若抛异常,则此函数无效果(强异常保证)。


移除首元素 (公开成员函数)
void pop_front();
   
   

移除容器首元素。若容器中无元素,则行为未定义。

指向被擦除元素的迭代器和引用被非法化。若元素是容器中的最后元素,则尾后迭代器是否被非法化是未指定的。其他迭代器和引用不受影响。 (C++11 前)
指向被擦除元素的迭代器和引用被非法化。若元素是容器的最后元素,则尾后迭代器亦被非法化。其他迭代器和引用不受影响。 (C++11 起)

参数

(无)

返回值

(无)

复杂度

常数。

异常

不抛出。


改变容器中可存储元素的个数 (公开成员函数)
void resize( size_type count, T value = T() );
 (C++11 前)
void resize( size_type count );
(1)(C++11 起)
void resize( size_type count, const value_type& value );
(2)(C++11 起)
   

重设容器大小以容纳 count 个元素。

若当前大小大于 count ,则减小容器为其首 count 个元素。

若当前大小小于 count ,则后附额外元素,并以 value 的副本初始化。

(C++11 前)

若当前大小小于 count ,

1) 则后附额外的 默认插入的元素
2) 则后附额外的  value 的副本
(C++11 起)

参数

count-容器的大小
value-用以初始化新元素的值
类型要求
-
 为使用重载 (1) , T 必须满足 MoveInsertable 和 DefaultInsertable 的要求。
-
 为使用重载 (2) , T 必须满足 CopyInsertable 的要求。

返回值

(无)

复杂度

与当前大小和 count 间的差成线性。。


交换内容 (公开成员函数)
void swap( deque& other );
 (C++17 前)
void swap( deque& other ) noexcept(/* see below */);
 (C++17 起)
   

将内容与 other 的交换。不在单个元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。


若 std::allocator_traits<allocator_type>::propagate_on_container_swap::value 为 true ,则用非成员 swap 的非限定调用交换分配器。否则,不交换它们(且若 get_allocator() != other.get_allocator() ,则行为未定义)。 (C++11 起)

参数

other-要与之交换内容的容器

返回值

(无)

异常

(无)

(C++17 前)
noexcept 规定:  
noexcept(std::allocator_traits<Allocator>::is_always_equal::value)
(C++17 起)

复杂度

常数。



#include<iostream>
#include<string>
#include<deque>
#include<ctime>
#include<vector>
using namespace std;

int main()
{
	deque<string> str;
	str.push_back("Hello");
	str.push_back("World");
	cout << "str: " << str.at(0) << " size:" << str.size() << endl;
	str.clear();
	if (!str.empty())
		cout << "str: " << str.at(0) << endl;
	else
	    cout<< "size:" << str.size() << endl;

	deque<int> mydeque;


	//插入
	// set some initial values:
	for (int i = 1; i<6; i++)
		mydeque.push_back(i); // 1 2 3 4 5

	deque<int>::iterator it = mydeque.begin();
	                    ++it;

	it = mydeque.insert(it, 10);                  // 1 10 2 3 4 5
	// "it" now points to the newly inserted 10

	mydeque.insert(it, 2, 20);                     // 1 20 20 10 2 3 4 5
	// "it" no longer valid!

	it = mydeque.begin() + 2;

	vector<int> myvector(2, 30);
	mydeque.insert(it, myvector.begin(), myvector.end());
	// 1 20 30 30 20 10 2 3 4 5

	cout << "mydeque contains:";
	for (it = mydeque.begin(); it != mydeque.end(); ++it)
		cout << ' ' << *it;
	cout << '\n';

	deque<int> mydeque1 = { 10, 20, 30 };

	auto it1 = mydeque1.emplace(mydeque1.begin() + 1, 100);
	mydeque1.emplace(it1, 200);
	mydeque1.emplace(mydeque1.end(), 300);

	cout << "mydeque contains:";
	for (auto& x : mydeque1)
		cout << ' ' << x;
	cout << '\n';

	mydeque1.emplace_back(100);
	mydeque1.emplace_back(200);

	cout << "mydeque contains:";
	for (auto& x : mydeque1)
		cout << ' ' << x;
	cout << '\n';


	deque<string> str1;
	str1.push_back("Hello");
	str1.push_back("world");
	cout << "str1: " << str1.at(0) << " size:" << str1.size() << endl;
	str1.erase(str1.begin());
	if (!str1.empty())
		cout << "str1: " << str1.at(0) << " size:" << str1.size() << endl;
	else
		cout << "size:" << str1.size() << endl;



	deque<int> arr{ 1, 2, 3, 4, 5, 6 };
	for (deque<int>::iterator it = arr.begin(); it != arr.end(); it++)
		cout << *it << ' ';
	cout << endl;

	//移除末元素 
	arr.pop_back();
	for (deque<int>::iterator it = arr.begin(); it != arr.end(); it++)
		cout << *it << ' ';
	cout << endl;

	//移除首元素 
	arr.pop_front();
	for (deque<int>::iterator it = arr.begin(); it != arr.end(); it++)
		cout << *it << ' ';
	cout << endl;

	//首元素插入
	arr.push_front(6);
	arr.push_front(6);
	arr.push_front(6);
	for (deque<int>::iterator it = arr.begin(); it != arr.end(); it++)
		cout << *it << ' ';
	cout << endl;

	
	deque<int>arr1(5, 9);
	cout << "arr1 size:" << arr1.size() << endl;
	arr1.swap(arr);
	
	cout << "arr1 size:" << arr1.size() << endl;
	for (deque<int>::iterator it = arr.begin(); it != arr.end(); it++)
		cout << *it << ' ';
	cout << endl;

	system("pause");
	return 0;
}

6、

非成员函数

按照字典顺序比较 deque 中的值 (函数模板)
template< class T, class Alloc >

bool operator==( const deque<T,Alloc>& lhs,

                 const deque<T,Alloc>& rhs );
(1)  
template< class T, class Alloc >

bool operator!=( const deque<T,Alloc>& lhs,

                 const deque<T,Alloc>& rhs );
(2)  
template< class T, class Alloc >

bool operator<( const deque<T,Alloc>& lhs,

                const deque<T,Alloc>& rhs );
(3)  
template< class T, class Alloc >

bool operator<=( const deque<T,Alloc>& lhs,

                 const deque<T,Alloc>& rhs );
(4)  
template< class T, class Alloc >

bool operator>( const deque<T,Alloc>& lhs,

                const deque<T,Alloc>& rhs );
(5)  
template< class T, class Alloc >

bool operator>=( const deque<T,Alloc>& lhs,

                 const deque<T,Alloc>& rhs );
(6)  
   

比较二个容器的内容。

1-2) 检查  lhs 与  rhs 的内容是否相等,即是否  lhs.size() == rhs.size() 且每个  lhs 中的元素与  rhs 的同位置元素比较相等。
3-6) 按字典序比较  lhs 与  rhs 的内容。按照等价于  std::lexicographical_compare 的函数进行比较。

参数

lhs, rhs-要比较内容的容器
-
 为使用重载 (1-2) , T 必须满足 EqualityComparable 的要求。
-
 为使用重载 (3-6) , T 必须满足 LessThanComparable 的要求。顺序关系必须建立全序。

返回值

1) 若容器内容相等则为  true ,否则为  false
2) 若容器内容不相等则为  true ,否则为  false
3) 若  lhs 的内容按字典序 小于  rhs 的内容则为  true ,否则为  false
4) 若  lhs 的内容按字典序 小于等于  rhs 的内容则为  true ,否则为  false
5) 若  lhs 的内容按字典序 大于  rhs 的内容则为  true ,否则为  false
6) 若  lhs 的内容按字典序 大于等于  rhs 的内容则为  true ,否则为  false

复杂度

与容器大小成线性


特化 std::swap 算法 (函数模板)
template< class T, class Alloc >

void swap( deque<T,Alloc>& lhs, 

           deque<T,Alloc>& rhs );
 (C++17 前)
template< class T, class Alloc >

void swap( deque<T,Alloc>& lhs, 

           deque<T,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)
   

为 std::deque 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs-要交换内容的容器

返回值

(无)

复杂度

常数。

异常

noexcept 规定:  
noexcept(noexcept(lhs.swap(rhs)))
(C++17 起)



// deque comparisons
#include <iostream>
#include <deque>

int main()
{
	std::deque<int> foo(3, 100);   // three ints with a value of 100
	std::deque<int> bar(2, 200);   // two ints with a value of 200

	if (foo == bar) std::cout << "foo and bar are equal\n";
	if (foo != bar) std::cout << "foo and bar are not equal\n";
	if (foo< bar) std::cout << "foo is less than bar\n";
	if (foo> bar) std::cout << "foo is greater than bar\n";
	if (foo <= bar) std::cout << "foo is less than or equal to bar\n";
	if (foo >= bar) std::cout << "foo is greater than or equal to bar\n";

	system("pause");
	return 0;
}


注意:与deque的成员函数swap区别
// swap (deque overload)
#include <iostream>
#include <deque>

int main()
{
	unsigned int i;
	std::deque<int> foo(3, 100);   // three ints with a value of 100
	std::deque<int> bar(5, 200);   // five ints with a value of 200

	swap(foo, bar);

	std::cout << "foo contains:";
	for (std::deque<int>::iterator it = foo.begin(); it != foo.end(); ++it)
		std::cout << ' ' << *it;
	std::cout << '\n';

	std::cout << "bar contains:";
	for (std::deque<int>::iterator it = bar.begin(); it != bar.end(); ++it)
		std::cout << ' ' << *it;
	std::cout << '\n';

	system("pause");
	return 0;
}


待续。。。。。。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HySmiley

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值