20.STL中list与queue之间的区别
20.STL中list与queue之间的区别
std::list
和 std::queue
是 C++ 标准库中的两个不同容器,它们之间有以下几点区别:
- 容器类型:
std::list
是一个双向链表,而std::queue
是一个队列,可以使用多种实现方式(如顺序容器、优先队列等)。 - 插入和删除元素:在
std::list
中,可以在任何位置插入和删除元素,而在std::queue
中,只能在队尾插入元素,从队头删除元素。 - 访问元素:在
std::list
中,可以随机访问元素,而在std::queue
中,只能顺序访问元素。 - 存储方式:
std::list
采用链表存储元素,而std::queue
采用顺序容器或优先队列等实现方式存储元素。 - 适用场景:
std::list
适用于需要在任意位置进行插入和删除操作的场景,而std::queue
适用于进行先进先出操作的场景。
总之,std::list
和 std::queue
是两种不同类型的容器,具有不同的特点和适用场景。需要根据具体需求选择合适的容器。
一、STL中的list
1.list的介绍
1.list是序列容器,允许在序列中的任何位置执行固定O(1)时间复杂度的插入和删除操作,并在两个方向进行迭代。
2.list容器使用双链表实现;双链表将每个元素存储在不同的位置,每个节点通过next,prev指针链接成顺序表。
3.list与其他标准序列容器(array,vector和deque)相比,list通常可以在容器内的任何位置插入、提取和移动元素。
4.list与其他标准序列容器(array,vector和deque)相比,list和forward_list(单链表实现)的主要缺点是他们不能通过位置直接访问元素;例如,要访问列表中的第五个元素,必须从已知位置(开始或结束)迭代到该位置,需要线性时间开销。
5.存储密度低,list要使用一些额外的内容空间(next,prev)来保持与每个元素相关联(前后续的线性)的链接信息,从而导致存储小元素类型(如char,short,int等)的列表的存储密度低。
2.list函数说明
2.1成员类型
成员类型 | 定义 |
---|---|
value_type | T |
allocator_type | Allocator |
size_type | 无符号整数类型(通常是 std::size_t ) |
difference_type | 有符号整数类型(通常是 std::ptrdiff_t ) |
reference | value_type& |
const_reference | const value_type& |
pointer | value_type* |
const_pointer | const value_type* |
iterator | 指向 value_type 的双向迭代器 |
const_iterator | 指向 const value_type 的双向迭代器 |
reverse_iterator | std::reverse_iterator |
const_reverse_iterator | std::reverse_iterator<const_iterator> |
2.2构造函数
函数 | 功能 |
---|---|
list(); | 默认构造函数。构造拥有默认构造的分配器的空容器 |
list( size_type count,const T& value); | 构造拥有 count 个有值 value 的元素的容器。 |
explicit list( size_type count ); | 构造拥有个 count 默认插入的 T 实例的容器。 |
list( InputIt first, InputIt last, const Allocator& alloc = Allocator() ); | 构造拥有范围 [first, last) 内容的容器。 |
list( const list& other ); | 复制构造函数。构造拥有 other 内容的容器。 |
list& operator=( const list& other ); | 复制赋值运算符。以 other 的副本替换内容。 |
list& operator=( std::initializer_list ilist ); | 以 initializer_list ilist 所标识者替换内容。 |
void assign( size_type count, const T& value ); | 以 count 份 value 的副本替换内容。 |
template< class InputIt > | |
void assign( InputIt first, InputIt last ); | 以范围 [first, last) 中元素的副本替换内容。 |
void assign( std::initializer_list ilist ); | 以来自 initializer_list ilist 的元素替换内容 |
例子:
#include <iostream>
#include <list>
using namespace std;
template<class T>
void Print(const list<T>& my)
{
class list<T>::const_iterator it = my.begin();
for (; it != my.end(); it++)
{
cout << *it << "\t";
}
cout << endl;
}
int main()
{
list<int> list1 = { 12,23,34 };
list<int> list2(3, 11);
list<int> list3(list2);
list<string> list4 = { "This","is","windows" };
list<string> list5;
list<string> list6;
list5 = list4;
list6.assign(3, "This");
Print(list1);
Print(list2);
Print(list3);
Print(list4);
Print(list5);
Print(list6);
return 0;
}
输出:
12 23 34
11 11 11
11 11 11
This is windows
This is windows
This This This
2.3元素访问
元素访问 | 功能 |
---|---|
reference front(); | 返回到容器首元素的引用 |
const_reference front() const; | 返回到容器首元素的引用 |
reference back(); | 返回到容器中最后一个元素的引用 |
const_reference back() const; | 返回到容器中最后一个元素的引用 |
例子:
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> list1 = { 12,23,34 };
cout << "list1.front():" << list1.front() << endl;
cout << "list1.back():" << list1.back() << endl;
return 0;
}
输出:
list1.front():12
list1.back():34
2.4迭代器
迭代器 | 功能 |
---|---|
iterator begin(); | 返回指向 list 首元素的迭代器 |
若 list 为空,则返回的迭代器将等于 end() | |
const_iterator begin() const; | 返回指向 list 首元素的迭代器 |
若 list 为空,则返回的迭代器将等于 end() | |
iterator end(); | 返回指向 list 末元素后一元素的迭代器 |
const_iterator end() const; | 返回指向 list 末元素后一元素的迭代器 |
reverse_iterator rbegin(); | 返回指向逆向 list 首元素的逆向迭代器 |
const_reverse_iterator rbegin() const; | 返回指向逆向 list 首元素的逆向迭代器 |
reverse_iterator rend(); | 返回指向逆向 list 末元素后一元素的逆向迭代器 |
const_reverse_iterator rend() const; | 返回指向逆向 list 末元素后一元素的逆向迭代器 |
例子:
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> list1 = { 12,23,34 };
list<int>::const_iterator it1 = list1.begin();
for (; it1 != list1.end(); it1++)
{
cout << *it1 << "\t";
}
cout << endl;
list<int>::reverse_iterator it2 = list1.rbegin() ;
for (; it2 != list1.rend(); it2++)
{
cout << *it2 << "\t";
}
cout << endl;
return 0;
}
输出:
12 23 34
34 23 12
2.5容量
容量 | 功能 |
---|---|
bool empty() const; | 检查容器是否无元素,即是否 begin() == end() |
size_type size() const; | 返回容器中的元素数,即 std::distance(begin(), end()) |
size_type max_size() const; | 返回根据系统或库实现限制的容器可保有的元素最大数量,即对于最大容器的 std::distance(begin(), end()) |
例子:
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> list1 = { 12,23,34 };
cout << "list1.empty():" << list1.empty() << endl;
cout << "list1.size():" << list1.size() << endl;
cout << "list1.max_size():" << list1.max_size() << endl;
return 0;
}
输出:
list1.empty():0
list1.size():3
list1.max_size():768614336404564650
2.6修改器
修改器 | 功能 |
---|---|
void clear(); | 从容器擦除所有元素。此调用后 size() 返回零 |
iterator insert( iterator pos, const T& value ); | 在 pos 前插入 value |
void insert( iterator pos, size_type count, const T& value ); | 在 pos 前插入 value 的 count 个副本 |
template< class InputIt > | |
void insert( iterator pos, InputIt first, InputIt last); | 在 pos 前插入来自范围 [first, last) 的元素 |
iterator insert( const_iterator pos, std::initializer_list ilist ); | 在 pos 前插入来自 initializer_list ilist 的元素 |
iterator erase( iterator pos ); | 移除位于 pos 的元素 |
iterator erase( iterator first, iterator last ); | 移除范围 [first; last) 中的元素 |
void pop_back(); | 移除容器的末元素 |
void push_front( const T& value ); | 前附给定元素 value 到容器起始 |
void push_back( const T& value ); | 后附给定元素 value 到容器尾 |
void pop_front(); | 移除容器首元素 |
void resize( size_type count ); | 重设容器大小以容纳 count 个元素 |
void resize( size_type count, T value = T() ); | count - 容器的大小,value - 用以初始化新元素的值 |
void swap( list& other ); | 将内容与 other 的交换 |
例子:
#include <iostream>
#include <list>
using namespace std;
template<class T>
void Print(const list<T>& my)
{
typename list<T>::const_iterator it = my.begin();
for (; it != my.end(); it++)
{
cout << *it << "\t";
}
cout << endl;
}
int main()
{
list<int> list1 = { 12,23,34 };
list<int> list2 = { 1,2,3,4,5 };
Print(list1);
Print(list2);
auto it = list1.begin();
list1.insert(it, 55);
Print(list1);
it++;
list1.insert(it, 3, 55);
Print(list1);
list1.erase(it);
Print(list1);
list1.swap(list2);
Print(list1);
Print(list2);
return 0;
}
输出:
12 23 34
1 2 3 4 5
55 12 23 34
55 12 55 55 55 23 34
55 12 55 55 55 34
1 2 3 4 5
55 12 55 55 55 34
2.7操作
操作 | 功能 |
---|---|
void merge( list& other ); | 归并二个已排序链表为一个。链表应以升序排序 |
void splice( const_iterator pos, list& other ); | 从 other 转移所有元素到 *this 中。元素被插入到 pos 所指向的元素之前。操作后容器 other 变为空 |
void splice( const_iterator pos, list& other, const_iterator it ); | 从 other 转移 it 所指向的元素到 *this 。元素被插入到 pos 所指向的元素之前 |
void splice( const_iterator pos, list& other, const_iterator first, const_iterator last); | 从 other 转移范围 [first, last) 中的元素到 *this 。元素被插入到 pos 所指向的元素之前 |
void remove( const T& value ); | 移除所有满足特定标准的元素。value - 要移除的元素的值 |
void reverse(); | 逆转容器中的元素顺序 |
void unique(); | 从容器移除所有相继的重复元素。只留下相等元素组中的第一个元素 |
void sort(); | 以升序排序元素。保持相等元素的顺序。用 operator< 比较元素 |
template< class Compare > | |
void sort( Compare comp ); | 以升序排序元素。保持相等元素的顺序。用给定的比较函数 comp |
例子:
#include <iostream>
#include <list>
using namespace std;
template<class T>
void Print(const list<T>& my)
{
typename list<T>::const_iterator it = my.begin();
for (; it != my.end(); it++)
{
cout << *it << "\t";
}
cout << endl;
}
int main()
{
list<int> list1 = { 2,1,9,5,3,7 };
list<int> list2 = { 1,8,3,6,0,1,5 };
Print(list1);
Print(list2);
list1.sort();
list2.sort();
Print(list1);
Print(list2);
list2.unique();
Print(list2);
list1.merge(list2);
Print(list1);
Print(list2);
return 0;
}
输出:
2 1 9 5 3 7
1 8 3 6 0 1 5
1 2 3 5 7 9
0 1 1 3 5 6 8
0 1 3 5 6 8
0 1 1 2 3 3 5 5 6 7 8 9
2.8vector和list区别
区别 | vector | list |
---|---|---|
底层实现 | 连续存储的容器,动态数组,在堆上分配空间 | 动态双向链表,在堆上 |
空间利用率 | 连续空间,不易造成内存碎片,空间利用率高 | 节点不连续,易造成内存碎片,小元素使节点密度低,空间利用率低 |
查询元素 | iterator operator[];find O(n);binary_search O(logn) | iterator find O(n) |
插入和删除 | 在最后插入(空间够):push_back(val);O(1)。在最后插入(空间不够):需要内存申请和释放,以及对之前数据进行拷贝。在之间插入(空间够):内存拷贝。在之间插入(空间不够):需要内存申请和释放,以及对之前数据进行拷贝。Insert(it,va) ,O(n)。在最后删除:pop_back(),O(1)。在之间删除:内存拷贝,不需要释放内存。erase(it),O(n)。resize(10):开辟空间,存储数据。reserve(10):只开辟空间,不存储数据。初始化vector空间,提高vector的使用效率。版权声明:本文为CSDN博主「愚蠢的土拨鼠。」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 | 插入:O(1),需要申请内存。push_back(),O(1);erase(it) ,O(n); |
迭代器 | 随机迭代器,迭代器检查越界。支持++,–,+,+=,<,>,!=,== | 双向迭代器,迭代器检查越界。支持++,–,==,!= |
迭代器失效 | 插入和删除元素都会导致迭代器失效 | 插入元素 |
总结
1.vector底层实现是数组;list是双向链表。
2.vector支持随机访问,list不支持。
3.vector是顺序内存,list不是。
4.vector在中间节点进行插入删除会导致内存拷贝,list不会。
5.vector一次性分配好内存,不够时才进行扩容;list每次插入新节点都会进行内存申请。
6.vector随机访问性能好,插入删除性能差;list随机访问性能差,插入删除性能好。
vector和list的使用场景
vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随机存取,而不在乎插入和删除的效率(很少使用插入和删除操作),选用vector
list 拥有一段不连续的内存空间,如果需要大量的插入和删除的操作,随机存取很少使用,选用list。
参考: C++中list详解_c++ list_愚蠢的土拨鼠。的博客-CSDN博客
3.1forward_list
forward_list为单向链表的泛化容器,与list双向链表容器一样,实现了线性表数据的链表存储,数据元素不必在物理内存中连续分布。STL中List是双向链表,而Slist是单向链表。它们的区别:Slist的迭代器是单向的Forward Iterator,而list的迭代器是双向的Bidirectional Iterator。Slist所耗用的空间更小,操作更快。它们共同的特点是,插入、移除、接合等操作并不会造成原有的迭代器失效。slist插入时,需要从前遍历,找到插入点的位置。为了更快插入,提供了insert_after,erase_after。slist提供push_front()操作,故其元素次序与元素插入顺序相反。
3.1forward_list技术原理
forward_list内部的链表由头指针、头节点和元素节点组成,每个节点含有指向后继节点的指针,最后一个节点的指针为null,可见forward_list没有形成一个环形回路。
头节点一般不存储数据,为了使各个元素节点都有前驱节点的指针指向它以便能够不加区别的对第一个元素节点和其他元素节点进行统一处理,所以构造头节点。
slist应用基础
list对象的创建和vector一样,不多解释。元素的删除、归并、排序与list相同。
使用时需要包含头文件
// 包含头文件
#include <forward_list>
3.2初始化
通常使用push_front函数进行初始化,由于slist的头节点仅有一个指针域保存首元素地址,而没有存放最后一个元素的地址,因此slist没有提供类似的push_back函数能够在容器尾部添加元素。push_front函数在链表首元素前面,插入一个新元素,使之成为首元素。
forward_list<类型名> | 链表名; 单向链表 |
---|---|
forward_list<int> f1; | 创建一个名为f1的单向链表,f1中的元素类型为int |
forward_list<int> f1(100,7); | f1中的元素为100个7 |
forward_list<int> f1{1,2,3,……}; | f1{1,2,3,……}; 元素为1,2,3,……的f1 |
forward_list<int> f2(f1); | 链表f2中包含和链表f1一样的元素 |
forward_list<int> f2=f1; | 链表f2中包含和链表f1一样的元素 |
3.3forward_list构造
构造函数 | 功能 |
---|---|
forward_list();(1) | 默认构造函数。构造拥有默认构造的分配器的空容器。 |
explicit forward_list(const Allocator& alloc);(2) | 构造拥有给定分配器 alloc 的空容器。 |
forward_list(size_type count, const T& value, const Allocator& alloc = Allocator());(3) (C++11 起) | 构造拥有 count 个有值 value 的元素的容器。 |
explicit forward_list(size_type count);(C++11 起)(4)(C++14 前) | |
explicit forward_list(size_type count, const Allocator& alloc = Allocator());(4)(C++14 起) | 构造拥有 count 个 默认插入的 T 实例的容器。不进行复制。 |
template< class InputIt > forward_list(InputIt first, InputIt last, const Allocator& alloc = Allocator());(5) (C++11 起) |
构造拥有范围 [first, last) 内容的容器。如果 InputIt 是整数类型,那么此构造函数拥有的效果同forward_list(static_cast<size_type>(first), static_cast<value_type>(last), a)。 (C++11 前)此重载只有在 InputIt 满足老式输入迭代器 (LegacyInputIterator) 时才会参与重载决议,以避免和重载 (3) 的歧义。(C++11 起) |
forward_list(const forward_list& other);(6) (C++11 起) | 复制构造函数。构造拥有 other 内容的容器。 如同通过调用 std::allocator_traits<allocator_type>::select_on_container_copy_construction( other.get_allocator()) 获得分配器。 |
forward_list(const forward_list& other, const Allocator& alloc);(7) (C++11 起) | 构造拥有 other 内容的容器,以 alloc 为分配器。 在进行类模板实参推导时,只会从首个实参推导模板形参 Allocator 。(C++23 起) |
forward_list(forward_list&& other);(8) (C++11 起) | 移动构造函数。用移动语义构造拥有 other 内容的容器。分配器通过属于 other 的分配器移动构造获得。 |
forward_list(forward_list&& other, const Allocator& alloc);(9) (C++11 起) | 有分配器扩展的移动构造函数。以 alloc 为新容器的分配器,从 other 移动内容;如果 alloc != other.get_allocator() ,那么它会导致逐元素移动。在进行类模板实参推导时,只会从首个实参推导模板形参 Allocator 。(C++23 起) |
forward_list(std::initializer_list |
构造拥有 initializer_list init 内容的容器。 |
参数
alloc | 用于此容器所有内存分配的分配器 |
---|---|
count | 容器的大小 |
value | 以之初始化容器元素的值 |
first, last | 复制元素的来源范围 |
other | 用作初始化容器元素来源的另一容器 |
init | 用作初始化元素来源的 initializer_list |
构造、复制与析构
函数 | 功能 |
---|---|
forward_list<Elem> c; | 默认构造函数;创建一个空forward_list |
forward_list<Elem> c(c2); | 复制构造函数;创建一个新的forward_list作为c2的副本(所有元素都被复制) |
forward_list<Elem> c = c2; | 复制构造函数;创建一个新的forward_list作为c2的副本(所有元素都被复制) |
forward_list<Elem> c(rv); | 移动构造函数;使用右值对象rv创建一个新forward_list |
forward_list<Elem> c = rv; | 移动构造函数;使用右值对象rv创建一个新forward_list |
forward_list<Elem> c(n) ; | 使用默认构造函数创建含有n个元素的forward_list |
forward_list<Elem> c(n,elem) ; | 创建一个forward_list,并使用n个elem进行初始化 |
forward_list<Elem> c(beg,end) ; | 创建一个forward_list,并使用beg到end范围内的值进行初始化 |
forward_list<Elem> c(initlist); | 创建一个forward_list,并使用初始化列表进行初始化 |
forward_list<Elem> c = initlist; | 创建一个forward_list,并使用初始化列表进行初始化 |
c.~forward_list() ; | 销毁所有元素并释放内存 |
3.4赋值
表达式 | 功能 |
---|---|
c = c2; | 将c2所有元素赋值给c |
c = rv; | 将右值对象rv的所有元素移动赋值给c |
c = initlist; | 使用初始化列表进行赋值 |
c.assign(initlist); | 使用初始化列表进行赋值 |
c.assign(n,elem); | 使用n个elem元素进行赋值 |
c.assign(beg,end); | 使用beg到end范围内的元素进行赋值 |
c1.swap(c2); | 交换c1和c2的数 |
swap(c1,c2) | 交换c1和c2的数 |
3.5非变动性操作
表达式 | 功能 |
---|---|
c.empty() | 判断容器是否为空 |
c.max_size() | 返回可容纳的元素最大数量 |
c1 == c2 | 判断c1与c2是否相等 |
c1 != c2 | 判断c1与c2是否不相等,等同于!(c1==c2) |
c1 < c2 | 判断c1是否小于c2 |
c1 > c2 | 判断c1是否大于c2 |
c1 <= c2 | 判断c1是否小于等于c2 |
c1 >= c2 | 判断c1是否大于等于c2 |
3.6迭代器相关函数
表达式 | 功能 |
---|---|
c.begin() | 返回一个双向迭代器,指向第一个元素 |
c.end() | 返回一个双向迭代器,指向最后一个元素 |
c.cbegin() | 返回一个双向常迭代器,指向第一个元素 |
c.cend() | 返回一个双向常迭代器,指向最后一个元素 |
c.before_begin() | 返回一个前向迭代器,指向第一个元素之前的位置 |
c.cbefore_begin() | 返回一个前向常迭代器,指向第一个元素之前的位置 |
3.7插入和移除元素
表达式 | 功能 |
---|---|
c.push_front(elem) | 在头部添加一个elem副本 |
c.pop_front() | 移除头部元素(但不回传) |
c.insert_after(pos,elem) | 在迭代器位置之后插入一个elem副本,并返回新元素的位置 |
c.insert_after(pos,n,elem) | 在迭代器位置之后插入n个elem副本,并返回第一个新元素的位置;若无新插入值,返回原位置 |
c.insert_after(pos,beg,end) | 在迭代器位置之后插入范围beg到end的所有元素的副本,并返回第一个新元素的位置;若无新插入值,返回原位置 |
c.insert_after(pos,initforward_list) | 在迭代器位置之后插入初始化列表的所有元素的副本,并返回第一个新元素的位置;若无新插入值,返回原位置 |
c.emplace_after(pos,args...) | 在迭代器位置之后插入一个使用args初始化的元素副本,并返回新元素的位置 |
c.emplace_front(args...) | 在头部添加一个使用args初始化的元素副本,无返回值 |
c.erase_after(pos) | 移除迭代器位置的元素,无返回值 |
c.erase_after(beg,end) | 移除beg到end范围内的所有元素,无返回值 |
c.remove(val) | 移除所有值为val的元素 |
c.remove_if(op) | 移除所有满足op条件的元素 |
c.resize(num) | 将元素数量设为num(如果size()增大,多出来的元素使用默认构造函数创建) |
c.resize(num,elem) | 将元素数量设为num(如果size()增大,多出来的元素都是elem的副本) |
c.clear() | 移除所以元素,清空容器 |
3.8特殊修改操作
表达式 | 功能 |
---|---|
c.unique() | 若存在相邻而数值相等的元素,移除重复元素 |
c.unique(op) | 若存在相邻而数值相等的元素,且满足op条件时,移除重复元素 |
c.splice_after(pos,c2) | 将c2内的所有元素转移到c1内pos所指的位置之后 |
c.splice_after(pos,c2,c2pos) | 将c2内c2pos之后的元素转移到c1内pos所指的位置之后 |
c.splice_after(pos,c2,c2beg,c2end) | 将c2内从c2beg到c2end区间内的所有元素转移到c1内pos所指的位置之后 |
c.sort() | 以operator<为准则,对所有元素排序 |
c.sort(op) | 以op为准则,对所有元素排序 |
c.merge(c2) | 假设c1和c2都包含已序元素,将c2的全部元素转移到c1.并保证合并后的forward_list仍为已序 |
c.merge(c2,op) | 假设c1和c2都包含op原则下已序元素,将c2的全部元素转移到c1.并保证合并后的forward_list在op原则下仍为已序 |
c.reverse() | 将所有元素反序 |
二、queue
1.queue的简介
queue的中文译为队列,队列是一种数据结构。C语言中队列的定义及初始化以及一些相关操作实现起来较为繁琐,而C++的queue让这些都变得简便易实现。因为C++中有着许多关于queue的方法函数。
队列(queue)最大的特点就是先进先出。就是说先放入queue容器的元素一定是要先出队列之后,比它后进入队列的元素才能够出队列。
使用queue时需要包含头文件:
#include<queue>
2.queue初始化
格式:
queue<Type, Container> (<数据类型,容器类型>)
初始化时必须要有数据类型,容器可省略,省略时则默认为deque 类型
例子:
queue<int> q; //使用默认的双端队列为底层容器创建一个空的queue队列对象q,数据元素为int类型。
queue<int> q[20]; //规定队列元素数量
queue<int,list<int>> q1;
queue<int,list<int>> q2(q1);
/*复制构造函数(queue(const queue&)),用一个queue对象创建新的queue对象。
利用queue对象q1,创建一个以双向链表为底层容器的queue对象q2*/
注意:不能用vector容器初始化queue
因为queue转换器要求容器支持front()、back()、push_back()及 pop_front(),说明queue的数据从容器后端入栈而从前端出栈。所以可以使用deque(double-ended queue,双端队列)和list对queue初始化,而vector因其缺少pop_front(),不能用于queue。
3.queue中常用的函数
●front():返回 queue 中第一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue为空,返回值是未定义的。
●back():返回 queue 中最后一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue
为空,返回值是未定义的。
●push(const T& obj):在 queue 的尾部添加一个元素的副本。这是通过调用底层容器的成员函数 push_back()来完成的。
●push(T&& obj):以移动的方式在 queue 的尾部添加元素。这是通过调用底层容器的具有右值引用参数的成员函数push_back() 来完成的。
●pop():删除 queue 中的第一个元素。
●size():返回 queue 中元素的个数。
●empty():如果 queue 中没有元素的话,返回 true。
●emplace():用传给 emplace() 的参数调用 T 的构造函数,在 queue 的尾部生成对象。
●swap(queue<T> &other_q):将当前 queue 中的元素和参数 queue 中的元素交换。它们需要包含相同类型的元素。也可以调用全局函数模板 swap() 来完成同样的操作。
示例代码:
#include<iostream>
#include<queue>
using namespace std;
int main()
{
queue<int> q1; //定义一个数据类型为int的queue
//向队列中加入元素
q1.push(1);
q1.push(2);
q1.push(3);
q1.push(4);
queue<int> q2(q1);
cout << "q1队列中的元素个数为:" << q1.size() << endl;
//判断队列是否为空
if (q1.empty())
{
cout << "q1队列为空" << endl;
}
else
{
cout << "q1队列不为空" << endl;
}
cout << "q1队列的队首元素为:" << q1.front() << endl;
cout << "q1队列的队尾元素为:" << q1.back() << endl;
//队列中的队首元素出队
q1.pop();
cout << "将q1队列队首元素出队后,现在队列中的元素为2、3、4" << endl;
// 读取q2队列的头部元素
cout << "q2队列的头部元素是:" << q2.front() << endl;
// 读取q2队列的尾部元素
cout << "q2队列的尾部元素是:" << q2.back() << endl;
//q2调用emplace()
q2.emplace(5);
// 遍历队列中的所有元素
cout << "q2队列中的所有元素是:";
while (!q2.empty())
{
cout << q2.front() << " ";
q2.pop();
}
cout << endl;
queue<int> q3,q4; //定义一个数据类型为int的queue
//向队列中加入元素
q3.push(1);
q3.push(2);
q3.push(3);
q3.push(4);
q4.push(5);
q4.push(4);
q4.push(3);
q4.push(2);
q4.push(1);
q3.swap(q4);
// 遍历队列中的所有元素
cout << "q3队列中的所有元素是:";
while (!q3.empty())
{
cout << q3.front() << " ";
q3.pop();
}
cout << endl;
cout << "q4队列中的所有元素是:";
while (!q4.empty())
{
cout << q4.front() << " ";
q4.pop();
}
cout << endl;
return 0;
}
运行结果:
将元素1、2、3、4一一加入队列中后,队列中现在的元素为:1、2、3、4
队列中的元素个数为:4
队列不为空
队列的队首元素为:1
队列的队尾元素为:4
将队列队首元素出队后,现在队列中的元素为2、3、4
参考:陈童学哦
三、deque
deque,double ended queue即双端队列,是一种在两端均可以扩展或者收缩的序列化容器。deque可以在头部和尾部进行插入和删除操作。
1.介绍
(1)deque容器的存储结构
与vector容器采用连续的线性空间不同,deque容器存储数据的空间是由一段一段等长的连续空间构成,各段空间之间并不一定是连续的,可以位于在内存的不同区域,使用一个中控器(指针数组)map来指向这些一段一段的空间,如果当前段空间用完了,就添加一个新的空间并将它链接在头部或尾部。deque存储结构如下图所示:
deque特殊的存储结构使得它在头部和尾部插入删除元素的效率非常高,deque可以在头部再加一段空间存储元素,而vector由于采取一段连续存储空间存储元素,所以它在头部插入一个元素需要所有元素向后移动,效率极低。但是也正式因为deque这种特殊的存储结构,使得它的迭代器较于一般的迭代器更为复杂,虽然deque容器的迭代器也支持随机访问,但是访问元素的速度要低于vector。
头文件:
deque是C++ 标准模板库的一部分,因此,想要使用deque,需要在程序中包含头文件deque
#include<deque>
2.deque定义和初始化
格式:
包含头文件deque之后,我们可以使用下边的格式定义deque:
std::deque<object_type> variable_name;
object_type
规定了deque中可以存放哪种类型的元素。
variable_name
为deque名。
方式: 定义deque的常用方式如下所示:
deque<Type> v1; //v1是一个空deque,可存储元素类型为T,执行默认初始化
deque<Type> v2(v1); //v2中包含v1中的所有元素
deque<Type> v2 = v1; //等价于v2(v1)
deque<Type> v3(n,value); //v3中有n个元素,并且值都为value
deque<Type> v4(n); //v4包含了n个重复执行了值初始化的对象
deque<Type> v5{a,b,c.....}; //v5包含大括号中的所有元素
deque<Type> v6 = {a,b,c...}; //等价于v5{a,b,c....}
示例代码
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> test;
deque<int> test1 = { 1, 2 };
deque<int> test2(test1);
deque<int> test3 = test1;
deque<int> test4(3, 2);
deque<int> test5(5);
deque<int> test6{ 1, 2, 3, 4, 5 };
deque<int> test7 = { 1, 2, 3, 4, 5, 6 };
cout << "test:";
for (auto a : test)
{
cout << a << " ";
}
cout << endl << "test1: ";
for (auto b : test1)
{
cout << b << " ";
}
cout << endl << "test2: ";
for (auto b : test2)
{
cout << b << " ";
}
cout << endl << "test3: ";
for (auto b : test3)
{
cout << b << " ";
}
cout << endl << "test4: ";
for (auto b : test4)
{
cout << b << " ";
}
cout << endl << "test5: ";
for (auto b : test5)
{
cout << b << " ";
}
cout << endl << "test6: ";
for (auto b : test6)
{
cout << b << " ";
}
cout << endl << "test7: ";
for (auto b : test7)
{
cout << b << " ";
}
return 0;
}
输出:
test:
test1: 1 2
test2: 1 2
test3: 1 2
test4: 2 2 2
test5: 0 0 0 0 0
test6: 1 2 3 4 5
test7: 1 2 3 4 5 6
3.deque的迭代器
deque中的迭代器包括以下几个,分别为:
●deque.begin():指向deque首元素的迭代器
●deque.end():指向deque尾元素下一个位置的迭代器
●deque.rbegin():指向deque尾元素的反向迭代器,即rbegin()指向尾元素,rbegin-1指向倒数第二个元素
●deque.rend():指向deque头元素前一个位置的反向迭代器,即rend()指向头元素前一个位置元素,rbegin-1指向第一个元素
●deque.cbegin():指向deque首元素的迭代器,与begin()相同,只不过增加了const属性,不能用于修改元素。
●deque.cend():指向deque尾元素下一个位置的迭代器,与end()相同,只不过增加了const属性,不能用于修改元素。
●deque.crbegin():指向deque尾元素的反向迭代器,与rbegin()相同,只不过增加了const属性,不能用于修改元素。
●deque.crend():指向deque头元素前一个位置的反向迭代器,与rend()相同,只不过增加了const属性,不能用于修改元素。
deque迭代器示意图如下:
代码示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> test = { 1, 2, 3, 4 };
cout << "初始化后deque为: ";
for (auto num : test)
{
cout << num << " ";
}
cout << endl;
// deque.begin()为指向deque头元素的迭代器
deque<int>::iterator begin_iterator = test.begin();
cout << "begin() 指向的元素:" << *begin_iterator << endl;
// deque.end()为指向deque尾元素后一个位置的迭代器,则test.end()-1指向尾元素
auto end_iterator = test.end();
cout << "end()-1 指向的元素:" << *(end_iterator - 1) << endl;
// deque.rbegin()为指向尾元素的迭代器,即反向(r)的头(begin)迭代器
auto rbegin_iterator = test.rbegin();
cout << "rbegin() 指向的元素:" << *rbegin_iterator << endl;
// deque.rend()为指向头元素的前一个位置的迭代器,即反向(r)尾(end)迭代器,则test.rend()-1指向头元素
auto rend_iterator = test.rend();
cout << "rend()-1 指向的元素:" << *(rend_iterator - 1) << endl;
// deque.cbegin()为指向deque头元素的const迭代器
// 与begin()不同的是返回迭代器类型为deque<int>::const_iterator,不可修改元素
deque<int>::const_iterator cbegin_iterator = test.cbegin();
cout << "cbegin() 指向的元素:" << *cbegin_iterator << endl;
// deque.cend()为指向deque尾元素下一个位置的const迭代器
// 与end()不同的是返回迭代器类型为deque<int>::const_iterator,不可修改元素
deque<int>::const_iterator cend_iterator = test.cend();
cout << "cend()-1 指向的元素:" << *(cend_iterator - 1) << endl;
// deque.crbegin()为指向尾元素的const迭代器,即反向(r)的const(c)头(begin)迭代器
auto crbegin_iterator = test.crbegin();
cout << "crbegin() 指向的元素: " << *crbegin_iterator << endl;
// deque.crend()为指向头元素下一个位置的const迭代器,即反向(r)的const(c)尾(end)迭代器
auto crend_iterator = test.crend();
cout << "crend()-1 指向的元素: " << *(crend_iterator - 1) << endl;
return 0;
}
输出:
初始化后deque为: 1 2 3 4
begin() 指向的元素:1
end()-1 指向的元素:4
rbegin() 指向的元素:4
rend()-1 指向的元素:1
cbegin() 指向的元素:1
cend()-1 指向的元素:4
crbegin() 指向的元素: 4
crend()-1 指向的元素: 1
4.deque容器的成员方法
(1)size()——元素个数
要想知道deque中有多少元素,使用deque.size()方法,作用是返回deque中元素的个数。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque = { 2, 3 };
cout << "添加元素前mydeque.size() = " << mydeque.size() << endl;
// 在deque头部插入一个元素5
mydeque.push_front(5);
// 在deque尾部插入一个元素5
mydeque.push_back(1);
cout << "添加元素后mydeque.size() = " << mydeque.size() << endl;
}
输出:
添加元素前mydeque.size() = 2
添加元素后mydeque.size() = 4
(2)max_size()——最多能容纳元素个数:
要想知道deque最多可以有多少元素,使用deque.max_size()方法,作用是返回deque中最多能容纳元素个数(基本没用过)。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque = { 2, 3 };
cout << "mydeque最多可容纳元素个数尾max_size() = " << mydeque.max_size() << endl;
}
输出:
mydeque最多可容纳元素个数尾max_size() = 4611686018427387903
(3)resize(n)——改变deque大小为n
如果想要改变deque的size,使用deque.resize(n)方法,将deque的size改为n。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque = { 1, 2 };
// 把mydeque的大小设为5
mydeque.resize(5);
cout << "第一次resize后deque中元素为:";
for (auto a : mydeque)
{
cout << a << " ";
}
cout << endl;
// 把mydeque的大小设为1
mydeque.resize(1);
cout << "第二次resize后deque中元素为:";
for (auto a : mydeque)
{
cout << a << " ";
}
}
输出:
第一次resize后deque中元素为:1 2 0 0 0
第二次resize后deque中元素为:1
可以看到,执行resize(n)后,如果当前deque的size小于n,则会在deque的尾部新添加若干个值为初始值的元素使deque的size扩大到n。如果当前的size大于n,则会从deque尾部移除多余元素使deque的size缩小到n;
(4)empty()——判断deque是否为空
empty()方法用来判断deque中是否有元素,如果有元素,返回false;如果没有元素,返回true。即为空返回true,非空返回false。
示例代码:
#include<iostream>
#include<deque>
using std::cout;
using std::endl;
using std::deque;
int main()
{
deque<int> mydeque;
cout << "mydeque是否为空?" << mydeque.empty();
// 在deque尾部插入一个元素5
mydeque.push_back(5);
cout << "\nmydeque是否为空?" << mydeque.empty();
return 0;
}
输出:
mydeque是否为空?1
mydeque是否为空?0
(5)shrink_to_fit()——要求deque减小容量已适应元素个数 【C++11】
deque减小内存以适配size,即将分配给deque的内存减小到当前deque中元素实际使用的内存大小。由于deque的实现机制大多为一个动态数组,可以保留已被删除的元素的内存空间或者提前分配的额外内存空间以快速插入,因此一个deque分配的内存空间可能比deque保存当前元素所需的内存要多。使用shrink_to_fit()就会释放这些多余暂未被用到的内存。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque;
// 改变mydeque的大小为100,此时会分配给deque这100个元素所需要的内存
mydeque.resize(100);
cout << "mydeque.size() = " << mydeque.size() << "\n";
// 改变mydeque的大小为10,deque中后90个元素被删除
// 但是由于deque实现机制,这些元素被删除后,分配给他们的内存空间可以被保留
// 因此改变mydeque大小为10之后,可能会有额外的内存空间在mydeque中未被使用
mydeque.resize(10);
cout << "mydeque.size() = " << mydeque.size() << "\n";
// 减小mydeque的内存到实际mydeque使用的大小
mydeque.shrink_to_fit();
}
输出:
mydeque.size() = 100
mydeque.size() = 10
(6) at()——访问deque元素
使用元素的索引来访问deque,其中at(index)中index为索引,必须是合法的。
示例代码:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque;
// 初始化mydeque为{1,2,3,4,5}
for (int i = 1; i <= 5; i++)
{
mydeque.push_back(i);
}
cout << "初始化后的mydeque:";
for (auto num : mydeque)
{
cout << num << " ";
}
int num2 = mydeque.at(2);
cout << "\nmydeque中索引为2的元素为:" << num2;
return 0;
}
输出:
初始化后的mydeque:1 2 3 4 5
mydeque中索引为2的元素为:3
(7)front()和back()——访问deque头尾元素
front()返回deque第一个元素,back()返回deque最后一个元素
示例代码:
#include<iostream>
#include<deque>
using std::cout;
using std::endl;
using std::deque;
int main()
{
deque<int> mydeque{ 1,2,3,4,5,6,7,8 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
int front = mydeque.front();
int back = mydeque.back();
cout << "\nmydeque的头元素为:" << front;
cout << "\nmydeque的尾元素为:" << back;
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4 5 6 7 8
mydeque的头元素为:1
mydeque的尾元素为:8
(8)assign()——指定deque元素
assign的作用就是用新的元素替换deque中旧的元素
用法一:deque.assign(num,value)
这种用法会用num个value填充deque,如果操作前deque中有其他元素,会被覆盖掉。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
mydeque.assign(3, 2);
cout << "\nassign之后mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
assign之后mydeque为:2 2 2
用法二:deque.assign(iterator1,iterator2)
这种用法会用两个迭代器iterator1和iterator2之间的元素覆盖deque的元素,迭代器可以是原来deque的迭代器,也可以是其他deque的迭代器,注意区间是左闭右开[iterator1,iterator2),即iterator1指向的元素在区间内,iterator2指向的元素不在区间内,iterator2可以是deque.end()。
示例代码:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque1{ 1, 2, 3, 4 };
deque<int> mydeque2{ 5, 6, 7, 8 };
cout << "初始化后的mydeque1为:";
for (auto num : mydeque1)
{
cout << num << " ";
}
cout << "\n初始化后的mydeque2为:";
for (auto num : mydeque2)
{
cout << num << " ";
}
// it1指向mydeque1头元素的下一个元素,即第二的元素
deque<int>::iterator it1 = mydeque1.begin() + 1;
// it2指向mydeque1尾元素
deque<int>::iterator it2 = mydeque1.end() - 1;
// 用[*it1,*it2)的元素替换mydeque2中的元素
mydeque2.assign(it1, it2);
cout << "\nassign后的mydeque2为:";
for (auto num : mydeque2)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque1为:1 2 3 4
初始化后的mydeque2为:5 6 7 8
assign后的mydeque2为:2 3
用法三:deque.assign(address1,address2)
这种用法会用两个数组元素地址address1和address2之间的元素覆盖deque的元素,注意区间仍是左闭右开[*address1,*address2),即address1指向的元素在区间内,address2指向的元素不在区间内。用法2和用法3示例如下:
示例代码:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque1{ 1, 2, 3, 4 };
int a[5] = { 10,20,30,40,50 };
cout << "初始化后的mydeque1为:";
for (auto num : mydeque1)
{
cout << num << " ";
}
// a[2]为30,a[4]为50,则用[a[2],a[4])的元素替换mydeque1中元素
mydeque1.assign(&a[2], &a[4]);
cout << "\nassign后的mydeque1为:";
for (auto num : mydeque1)
{
cout << num << " ";
}
}
输出:
初始化后的mydeque1为:1 2 3 4
assign后的mydeque1为:30 40
(9)push_back()——添加元素(deque尾部)
向deque中添加元素,使用
push_back()
方法,作用是向deque尾部添加一个元素。示例如下:
示例代码:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// 在deque尾部插入一个元素8
mydeque.push_back(8);
cout << "\n尾部插入一个元素后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
尾部插入一个元素后的mydeque为:1 2 3 4 8
(10)push_front()——添加元素(deque头部)
向deque中添加元素,使用
push_front()
方法,作用是向deque头部添加一个元素。示例如下:
示例代码:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// 在deque尾部插入一个元素8
mydeque.push_front(8);
cout << "\n头部插入一个元素后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
头部插入一个元素后的mydeque为:8 1 2 3 4
(11)pop_back()——移除deque元素(尾部)
删除deque中的元素,使用
pop_back()
方法,作用是删除deque尾部的一个元素。示例如下:
示例代码:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// 删除mydeue尾部一个元素
mydeque.pop_back();
cout << "\n尾部删除一个元素后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
尾部删除一个元素后的mydeque为:1 2 3
(12)pop_front()——删除deque元素(头部)
删除deque中的元素,使用
pop_front()
方法,作用是删除deque头部的一个元素。示例如下:
示例代码:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// 删除mydeue头部一个元素
mydeque.pop_front();
cout << "\n头部删除一个元素后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
头部删除一个元素后的mydeque为:2 3 4
(13)insert()——添加元素(任意位置)
向deque中添加元素。
insert共有三种形式:
- insert(iterator,value);
- insert(iterator, num, value);
- insert(iterator, iterator1, iterator2);
用法一:deque.insert(iterator,value)
使用insert(iterator,value)方法,作用是向iterator迭代器指向元素的前边添加一个元素value,并返回一个迭代器指向新插入的元素。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// it指向mydeque的第二个元素
deque<int>::iterator it = mydeque.begin() + 1;
// 使用insert添加一个元素
deque<int>::iterator itnew = mydeque.insert(it, 10);
cout << "\n返回的迭代器指向的元素为" << *itnew;
cout << "\ninsert添加一个元素后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
返回的迭代器指向的元素为10
insert添加一个元素后的mydeque为:1 10 2 3 4
用法二:deque.insert(iterator,num,value)
使用
insert(iterator,num,value)
方法,作用是向iterator迭代器指向元素的前边添加num个元素value,并返回一个迭代器指向新插入的第一个元素.
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// it指向mydeque的第二个元素
deque<int>::iterator it = mydeque.begin() + 1;
// 定义一个辅助deque
deque<int> deque2{ 10, 20, 30 };
// it1指向deque2的第一个元素
deque<int>::iterator it1 = deque2.begin();
// it2指向deque2的最后一个元素后一个位置
deque<int>::iterator it2 = deque2.end();
// 使用insert在2之前添加[it1,it2)之间的元素
mydeque.insert(it, it1, it2);
cout << "\n使用insert插入元素后:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
使用insert插入元素后:1 20 20 2 3 4
用法三:insert(iterator, iterator1, iterator2);
使用方法,作用是向iterator迭代器指向元素的前边添加[iterator1,iterator2)之间的元素。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// it指向mydeque的第二个元素
deque<int>::iterator it = mydeque.begin() + 1;
// 定义一个辅助deque
deque<int> deque2{ 10, 20, 30 };
// it1指向deque2的第一个元素
deque<int>::iterator it1 = deque2.begin();
// it2指向deque2的最后一个元素后一个位置
deque<int>::iterator it2 = deque2.end();
// 使用insert在2之前添加[it1,it2)之间的元素
mydeque.insert(it, it1, it2);
cout << "\n使用insert插入元素后:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
使用insert插入元素后:1 10 20 30 2 3 4
(14)erase()——删除元素(任意位置)
erase的作用就是根据传入的迭代器删除deque中的元素,参数为一个迭代器,只删除迭代器指向的元素;参数为两个迭代器,删除两个迭代器之间的元素
用法一:deque.erase(iterator)
这种用法会删除迭代器iterator指向的元素。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// it指向mydeque的第二个元素
deque<int>::iterator it = mydeque.begin() + 1;
// 删除it指向的元素,即2,并返回一个迭代器指向2之后的元素
deque<int>::iterator itnew = mydeque.erase(it);
cout << "\n删除元素后返回的迭代器itnew指向的元素为:" << *itnew;
cout << "\n使用erase删除元素后:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
删除元素后返回的迭代器itnew指向的元素为:3
使用erase删除元素后:1 3 4
用法二:deque.erase(iterator1,iterator2)
这种用法会删除迭代器iterator1指向的元素到iterator2指向元素之间的元素,包括iterator1指向的元素但不包括iterator2指向的元素,即擦除[iterator1,iterator2)。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// it1指向mydeque的第二个元素
deque<int>::iterator it1 = mydeque.begin() + 1;
// it2指向mydeque的最后一个元素后一个位置
deque<int>::iterator it2 = mydeque.end();
// 删除[it1,it2)之间的元素,即删除2,3,4
mydeque.erase(it1, it2);
cout << "\n使用erase删除元素后:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
使用erase删除元素后:1
(15)clear()——清空元素
clear的作用就是清空deque中的所有元素
清空deque中所有元素,并且deque的大小变为0。使用
clear()
方法。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// 清除mydeque中所有元素
mydeque.clear();
cout << "\n使用erase清空元素后mydeque.size() =" << mydeque.size();
cout << "\n使用erase清空元素后:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
使用erase清空元素后mydeque.size() =0
使用erase清空元素后:
(16)swap()——交换元素
swap的作用就是交换两个deque的元素
交换两个deque的元素,使用
swap()
方法,deque1.swap(deque2)
,两个deque存储的元素类型必须相同,元素个数可以不同。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque1{ 1, 11, 111, 1111 };
deque<int> mydeque2{ 2, 22, 222 };
cout << "初始化后的mydeque1为:";
for (auto num : mydeque1)
{
cout << num << " ";
}
cout << "\n初始化后的mydeque1为:";
for (auto num : mydeque2)
{
cout << num << " ";
}
// 交换mydeque1和mydeque2的元素
mydeque1.swap(mydeque2);
cout << "\n使用swap交换元素后mydeque1:";
for (auto num : mydeque1)
{
cout << num << " ";
}
cout << "\n使用swap交换元素后mydeque2:";
for (auto num : mydeque2)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque1为:1 11 111 1111
初始化后的mydeque1为:2 22 222
使用swap交换元素后mydeque1:2 22 222
使用swap交换元素后mydeque2:1 11 111 1111
(17)emplace()——插入元素 【C++11】
向deque中添加元素,使用
emplace(iterator,value)
方法,作用是向iterator迭代器指向元素的前边添加一个元素value。返回一个迭代器,指向新添加的元素。
示例如下:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque1为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// it指向mydeque第二个元素,即2
deque<int>::iterator it = mydeque.begin() + 1;
// 向it指向元素(2)前插入元素10,并返回指向10的迭代器
deque<int>::iterator it1 = mydeque.emplace(it, 10);
cout << "\n第一次插入后返回的迭代器it1指向元素为:" << *it1;
// 向it1指向元素(10)前插入元素20,并返回指向20的迭代器
deque<int>::iterator it2 = mydeque.emplace(it1, 20);
cout << "\n第二次插入后返回的迭代器it2指向元素为:" << *it2;
// 向mydeque尾部插入元素30
mydeque.emplace(mydeque.end(), 30);
cout << "\n三次插入元素后,mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque1为:1 2 3 4
第一次插入后返回的迭代器it1指向元素为:10
第二次插入后返回的迭代器it2指向元素为:20
三次插入元素后,mydeque为:1 20 10 2 3 4 30
emplace和insert的区别:
emplace和insert插入元素最大的区别就是emplace不会产生不必要的变量,使用insert插入元素时,需要申请内存空间创建临时对象,而申请内存空间就需要消耗一定时间;而使用emplace插入元素时,直接在原来容器的内存空间上 ,调用构造函数,不需要额外申请内存空间,就节省了很多时间,效率较高。
(18)emplace_back()——在deque尾部插入元素 【C++11】
在容器尾部生成一个元素。和 push_back() 的区别是,该函数直接在容器尾部构造元素,省去了复制移动元素的过程。示例如下:
示例代码:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// 在deque尾部插入一个元素10
mydeque.emplace_back(10);
cout << "\n尾部插入一个元素后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
尾部插入一个元素后的mydeque为:1 2 3 4 10
(19)emplace_front()——在deque尾部插入元素 【C++11】
在容器头部生成一个元素。和 push_front() 的区别是,该函数直接在容器头部构造元素,省去了复制移动元素的过程。示例如下:
示例代码:
#include <deque>
#include <iostream>
using std::cout;
using std::deque;
using std::endl;
int main()
{
deque<int> mydeque{ 1, 2, 3, 4 };
cout << "初始化后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
// 在deque头部插入一个元素10
mydeque.emplace_front(10);
cout << "\n头部插入一个元素后的mydeque为:";
for (auto num : mydeque)
{
cout << num << " ";
}
return 0;
}
输出:
初始化后的mydeque为:1 2 3 4
头部插入一个元素后的mydeque为:10 1 2 3 4
参考:[deque用法深度解析,一篇文章弄懂deque容器各种操作](