📋 前言
- 🖱 博客主页:在下马农的碎碎念
- ✍ 本文由在下马农原创,首发于CSDN
- 📆 首发时间:2023/08/10
- 📅 最近更新时间:2023/08/10
- 🤵 此马非凡马,房星本是星。向前敲瘦骨,犹自带铜声。
- 📇 系列文章目录: 暂无
- 🙏作者水平有限,如发现错误,请留言轰炸哦!万分感谢!
- 🤗码字不易 欢迎关注🔎点赞👍收藏⭐️留言📝
我欲与君相知,长命无绝衰。
山无陵,江水为竭,冬雷震震,夏雨雪,
天地合,乃敢与君绝!
——《上邪》
以下是正文
1、list介绍
list是C++的一个序列容器,插入和删除元素的效率较高,时间复杂度为常数级别,list容器的底层数据结构为双向链表,这使得list的元素可以存储在非相邻的内存中,在list内部,不同元素之间通过指向前一个元素的指针以及指向后一个元素的指针相关联。
list容器和forward_list非常相似,他们之间最大的不同就是forward_list底层实现为单链表,只可以向一个方向进行迭代遍历。
与其他序列容器如vector deque array相比,由于其底层数据结构为双向链表,因此list在插入删除元素方面很有优势,在列表的任意位置进行插入和删除操作的时间复杂度为O(1)。但不能直接通过位置(下标)来直接访问元素。想要访问list的某个元素,必须从list的一端(或已知位置)迭代到该元素。另外,list还需要额外的存储空间来储存前一个元素和后一个元素的链接信息。
1.1 list容器的存储结构
list容器底层为双向链表,此外在一些STL版本中其底层使用的是双向循环链表,双向链表每个节点包含指向前驱节点的pre指针,指向后继节点的next指针以及节点的数据。list存储结构如下图所示:node表示链表第一个元素的指针
1.2 list容器优点:
- 高效的插入和删除:由于std::list是基于双向链表实现的,插入和删除操作在任意位置都具有常数时间复杂度O(1),不需要移动其他元素。这使得std::list在需要频繁插入和删除元素的场景下非常高效。
- 稳定的迭代器:在std::list中进行插入和删除操作不会使得迭代器失效。这意味着在插入或删除元素后,仍然可以继续使用之前获取的迭代器进行遍历和操作。
- 动态内存管理:std::list可以动态调整大小,根据需要分配和释放内存。这使得std::list能够有效地处理大量元素的情况,而不会浪费过多的内存空间。
1.3 list容器缺点:
- 低效的随机访问:由于std::list的存储结构是双向链表,访问元素时需要从头或尾开始遍历链表,因此在列表中进行随机访问的效率较低。获取特定位置的元素需要遍历链表,时间复杂度为O(n),其中n是元素的总数量。
- 占用额外内存:相较于其他容器,std::list在存储上需要额外的指针来维护链表结构,因此在存储大量元素时,它可能占用更多的内存空间。
- 迭代器不支持指针算术:std::list的迭代器不支持指针算术运算,无法像指针那样直接进行加减操作,这限制了一些操作的灵活性。
头文件:
list是C++ 标准模板库的一部分,因此,想要使用list,需要在程序中包含头文件 list
#include<list>
2、list定义和初始化
格式:
包含头文件list之后,我们可以使用下边的格式定义list:
std::list<T> myList; // 创建一个名为myList的空列表,其中T是列表中元素的类型
T
规定了list中可以存放哪种类型的元素。
myList
为list名。
方式: 定义list的常用方式如下所示:
list<Type> v1; //v1是一个空list,可存储元素类型为T,执行默认初始化
list<Type> v2(v1); //v2中包含v1中的所有元素
list<Type> v3 = v1; //等价于v2(v1)
list<Type> v4(n,value); //v3中有n个元素,并且值都为value
list<Type> v5(n); //v4包含了n个重复执行了值初始化的对象
list<Type> v6{a,b,c.....}; //v5包含大括号中的所有元素
list<Type> v7 = {a,b,c...}; //等价于v5{a,b,c....}
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> test;
list<int> test1 = {1, 2};
list<int> test2(test1);
list<int> test3 = test1;
list<int> test4(3, 2);
list<int> test5(5);
list<int> test6{1, 2, 3, 4, 5};
list<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 << " ";
}
}
📄输出📄
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
上边的例子中,使用各种方式初始化创建list,可以根据需要选择使用。
3、list的迭代器
list中的迭代器包括以下几个,分别为:
list.begin()
:指向list首元素的迭代器list.end()
:指向list尾元素下一个位置的迭代器list.rbegin()
:指向list尾元素的反向迭代器,即rbegin()指向尾元素,rbegin指向元素的前一个元素为倒数第二个元素list.rend()
:指向list头元素前一个位置的反向迭代器,即rend()指向头元素前一个位置元素,rend指向元素的后一个元素为第一个元素list.cbegin()
:指向list首元素的迭代器,与begin()相同,只不过增加了const属性,不能用于修改元素。list.cend()
:指向list尾元素下一个位置的迭代器,与end()相同,只不过增加了const属性,不能用于修改元素。list.crbegin()
:指向list尾元素的反向迭代器,与rbegin()相同,只不过增加了const属性,不能用于修改元素。list.crend()
:指向list头元素前一个位置的反向迭代器,与rend()相同,只不过增加了const属性,不能用于修改元素。
list迭代器示意图如下:
代码示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> test = {1, 2, 3, 4};
cout << "初始化后list为: ";
for (auto num : test) {
cout << num << " ";
}
cout << endl;
// list.begin()为指向list头元素的迭代器
list<int>::iterator begin_iterator = test.begin();
cout << "begin() 指向的元素:" << *begin_iterator << endl;
// list.end()为指向list尾元素后一个位置的迭代器,则test.end()指向位置的前一个元素是最后一个元素
auto end_iterator = test.end();
// end指向位置的前一个元素才是最后一个元素
end_iterator--;
cout << "end() 指向位置的前一个元素: " << *end_iterator << endl;
// list.rbegin()为指向尾元素的迭代器,即反向(r)的头(begin)迭代器
auto rbegin_iterator = test.rbegin();
cout << "rbegin() 指向的元素:" << *rbegin_iterator << endl;
// list.rend()为指向头元素的前一个位置的迭代器,即反向(r)尾(end)迭代器,则test.rend()指向位置的后一个元素指向头元素
auto rend_iterator = test.rend();
rend_iterator--;
cout << "rend()指向位置的后一个元素:" << *rend_iterator << endl;
// list.cbegin()为指向list头元素的const迭代器
// 与begin()不同的是返回迭代器类型为list<int>::const_iterator,不可修改元素
list<int>::const_iterator cbegin_iterator = test.cbegin();
cout << "cbegin() 指向的元素:" << *cbegin_iterator << endl;
// list.cend()为指向list尾元素下一个位置的const迭代器
// 与end()不同的是返回迭代器类型为list<int>::const_iterator,不可修改元素
list<int>::const_iterator cend_iterator = test.cend();
cend_iterator--;
cout << "cend()指向位置的前一个元素:" << *cend_iterator << endl;
// list.crbegin()为指向尾元素的const迭代器,即反向(r)的const(c)头(begin)迭代器
auto crbegin_iterator = test.crbegin();
cout << "crbegin() 指向的元素: " << *crbegin_iterator << endl;
// list.crend()为指向头元素下一个位置的const迭代器,即反向(r)的const(c)尾(end)迭代器
auto crend_iterator = test.crend();
crend_iterator--;
cout << "crend()指向位置的后一个元素: " << *crend_iterator << endl;
return 0;
}
📄输出📄
初始化后list为: 1 2 3 4
begin() 指向的元素:1
end() 指向位置的前一个元素: 4
rbegin() 指向的元素:4
rend()指向位置的后一个元素:1
cbegin() 指向的元素:1
cend()指向位置的前一个元素:4
crbegin() 指向的元素: 4
crend()指向位置的后一个元素: 1
4、list容器的成员方法
除了上述返回list迭代器的成员函数之外,list还有一些其他的成员函数
(1) size()——元素个数
要想知道list中有多少元素,使用list.size()方法,作用是返回list中元素的个数。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist1 = {2, 3};
list<int> mylist2 = {1, 2, 3, 4};
cout<< "mylist1中元素个数为 = "<< mylist1.size()<< endl;
cout<< "mylist2中元素个数为 = "<< mylist2.size()<< endl;
}
📄输出📄
mylist1中元素个数为 = 2
mylist2中元素个数为 = 4
(2) max_size()——最多能容纳元素个数:
要想知道list最多可以有多少元素,使用list.max_size()方法,作用是返回list中最多能容纳元素个数(基本没用过)。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist = {2, 3};
cout<< "mylist最多可容纳元素个数尾max_size() = "<< mylist.max_size()<<endl;
}
📄输出📄
mylist最多可容纳元素个数尾max_size() = 384307168202282325
(3) resize(n)——改变list大小为n
如果想要改变list的size,使用list.resize(n)方法,将list的size改为n。
在C++中,std::list提供了resize()方法,用于调整列表的大小。使用resize()方法可以重新指定list的大小,并根据需要插入或删除list中的元素来达到指定的大小。
resize()方法有两种重载形式:
-
void resize(size_type count, const T& value = T()):
这个重载会将列表的大小调整为count。如果count大于当前列表的大小,则在列表末尾插入足够数量的值为value的元素。如果count小于当前列表的大小,则删除超出count的元素。 -
void resize(size_type count):
这个重载会将列表的大小调整为count。如果count大于当前列表的大小,则在列表末尾插入默认构造的元素。如果count小于当前列表的大小,则删除超出count的元素。
💻示例代码💻
#include <iostream>
#include <list>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist = {1, 2};
// 把mylist的大小设为5
mylist.resize(5);
cout << "第一次resize后list中元素为:";
for (auto a : mylist) {
cout << a << " ";
}
cout << endl;
// 把mylist的大小设为1
mylist.resize(1);
cout << "第二次resize后list中元素为:";
for (auto a : mylist) {
cout << a << " ";
}
cout << endl;
// 把list大小设为4,不足部分填充5
mylist.resize(4, 5);
cout << "第三次resize后list中元素为:";
for (auto a : mylist) {
cout << a << " ";
}
cout << endl;
}
📄输出📄
第一次resize后list中元素为:1 2 0 0 0
第二次resize后list中元素为:1
第三次resize后list中元素为:1 5 5 5
(4) empty()——判断list是否为空
empty()方法用来判断list是否为空,如果为空,返回true;如果非空,返回false。示例如下:
💻示例代码💻
#include<iostream>
#include<list>
using std::cout;
using std::endl;
using std::list;
int main () {
list<int> mylist1;
list<int> mylist2 = {1, 2};
cout<< "mylist1是否为空?"<< mylist1.empty() << endl;
cout<< "mylist2是否为空?"<< mylist2.empty() << endl;
}
📄输出📄
mylist1是否为空?1
mylist2是否为空?0
(5) front()——访问list头元素
❤front()返回list第一个元素❤
示例如下:
💻示例代码💻
#include<iostream>
#include<list>
using std::cout;
using std::endl;
using std::list;
int main() {
list<int> mylist {1, 2, 3, 4, 5, 6, 7, 8};
cout<< "初始化后的mylist为:";
for (auto num : mylist) {
cout<< num<< " ";
}
int front = mylist.front();
cout<< "\nmylist的头元素为:"<< front;
}
📄输出📄
初始化后的mylist为:1 2 3 4 5 6 7 8
mylist的头元素为:1
(6) back()——访问list尾元素
❤back()返回list第一个元素❤
示例如下:
💻示例代码💻
#include<iostream>
#include<list>
using std::cout;
using std::endl;
using std::list;
int main() {
list<int> mylist {1, 2, 3, 4, 5, 6, 7, 8};
cout<< "初始化后的mylist为:";
for (auto num : mylist) {
cout<< num<< " ";
}
int front = mylist.front();
cout<< "\nmylist的头元素为:"<< front;
}
📄输出📄
初始化后的mylist为:1 2 3 4 5 6 7 8
mylist的头元素为:8
(7) assign()——指定list元素
❤assign的作用就是用新的元素替换list中旧的元素❤
用法一:list.assign(num,value)
这种用法会用num个value填充list,如果操作前list中有其他元素,会被覆盖掉。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
mylist.assign(3, 2);
cout << "\nassign之后mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
assign之后mylist为:2 2 2
用法二:list.assign(iterator1,iterator2)
这种用法会用两个迭代器iterator1和iterator2之间的元素覆盖list的元素,迭代器可以是原来list的迭代器,也可以是其他list的迭代器,注意区间是左闭右开[iterator1,iterator2),即iterator1指向的元素在区间内,iterator2指向的元素不在区间内,iterator2可以是list.end()。
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist1{1, 2, 3, 4};
list<int> mylist2{5, 6, 7, 8};
cout << "初始化后的mylist1为:";
for (auto num : mylist1) {
cout << num << " ";
}
cout << "\n初始化后的mylist2为:";
for (auto num : mylist2) {
cout << num << " ";
}
// it1指向mylist1头元素的下一个元素,即第二个元素
list<int>::iterator it1 = ++mylist1.begin();
// it2指向mylist1尾元素
list<int>::iterator it2 = --mylist1.end();
// 用[*it1,*it2)的元素替换mylist2中的元素
mylist2.assign(it1, it2);
cout << "\nassign后的mylist2为:";
for (auto num : mylist2) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist1为:1 2 3 4
初始化后的mylist2为:5 6 7 8
assign后的mylist2为:2 3
用法三:list.assign(address1,address2)
这种用法会用两个数组元素地址address1和address2之间的元素覆盖list的元素,注意区间仍是左闭右开[*address1,*address2),即address1指向的元素在区间内,address2指向的元素不在区间内。用法2和用法3示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist1{1, 2, 3, 4};
int a[5] = {10,20,30,40,50};
cout << "初始化后的mylist1为:";
for (auto num : mylist1) {
cout << num << " ";
}
// a[2]为30,a[4]为50,则用[a[2],a[4])的元素替换mylist1中元素
mylist1.assign(&a[2], &a[4]);
cout << "\nassign后的mylist1为:";
for (auto num : mylist1) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist1为:1 2 3 4
assign后的mylist1为:30 40
(8) push_back()——添加元素(list尾部)
向list中添加元素,使用
push_back()
方法,作用是向list尾部添加一个元素。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// 在list尾部插入一个元素8
mylist.push_back(8);
cout << "\n尾部插入一个元素后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
尾部插入一个元素后的mylist为:1 2 3 4 8
(9) push_front()——添加元素(list头部)
向list中添加元素,使用
push_front()
方法,作用是向list头部添加一个元素。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// 在list尾部插入一个元素8
mylist.push_front(8);
cout << "\n头部插入一个元素后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
头部插入一个元素后的mylist为:8 1 2 3 4
(10) pop_back()——移除list元素(尾部)
删除list中的元素,使用
pop_back()
方法,作用是删除list尾部的一个元素。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// 删除mydeue尾部一个元素
mylist.pop_back();
cout << "\n尾部删除一个元素后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
尾部删除一个元素后的mylist为:1 2 3
(11) pop_front()——删除list元素(头部)
删除list中的元素,使用
pop_front()
方法,作用是删除list头部的一个元素。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// 删除mydeue头部一个元素
mylist.pop_front();
cout << "\n头部删除一个元素后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
头部删除一个元素后的mylist为:2 3 4
(12) insert()——添加元素(任意位置)
向list中添加元素。
insert共有三种形式:
- insert(iterator, value);
- insert(iterator, num, value);
- insert(iterator, iterator1, iterator2);
用法一:list.insert(iterator,value)
使用
insert(iterator,value)
方法,作用是向iterator迭代器指向元素的前边添加一个元素value,并返回一个迭代器指向新插入的元素。
示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// it指向mylist的第二个元素
list<int>::iterator it = mylist.begin() + 1;
// 使用insert添加一个元素
list<int>::iterator itnew = mylist.insert(it, 10);
cout << "\n返回的迭代器指向的元素为" << *itnew;
cout << "\ninsert添加一个元素后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
返回的迭代器指向的元素为10
insert添加一个元素后的mylist为:1 10 2 3 4
用法二:list.insert(iterator,num,value)
使用
insert(iterator,num,value)
方法,作用是向iterator迭代器指向元素的前边添加num个元素value,并返回一个迭代器指向新插入的第一个元素.
示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// it指向mylist的第二个元素
list<int>::iterator it = mylist.begin() + 1;
// 使用insert添加2个元素,value为20
mylist.insert(it, 2, 20);
cout << "\n使用insert插入元素后:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
使用insert插入元素后:1 20 20 2 3 4
用法三:insert(iterator, iterator1, iterator2)
使用
insert(iterator, iterator1, iterator2);
方法,作用是向iterator迭代器指向元素的前边添加[iterator1,iterator2)之间的元素。
示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// it指向mylist的第二个元素
list<int>::iterator it = mylist.begin() + 1;
// 定义一个辅助list
list<int> list2{10, 20, 30};
// it1指向list2的第一个元素
list<int>::iterator it1 = list2.begin();
// it2指向list2的最后一个元素后一个位置
list<int>::iterator it2 = list2.end();
// 使用insert在2之前添加[it1,it2)之间的元素
mylist.insert(it, it1, it2);
cout << "\n使用insert插入元素后:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
使用insert插入元素后:1 10 20 30 2 3 4
用法四:insert(iterator, std::initializer_list)
使用
insert(iterator,std::initializer_list);
方法,作用是向iterator迭代器指向元素的前边添加初始化列表中的元素。
示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// it指向mylist的第二个元素
list<int>::iterator it = ++mylist.begin();
// 使用insert在2之前添加元素
mylist.insert(it, {100, 200, 300});
cout << "\n使用insert插入元素后:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
使用insert插入元素后:1 100 200 300 2 3 4
(13) erase()——删除元素(任意位置)
❤erase的作用就是根据传入的迭代器删除list中的元素,参数为一个迭代器,只删除迭代器指向的元素;参数为两个迭代器,删除两个迭代器之间的元素❤
用法一:list.erase(iterator)
这种用法会删除迭代器iterator指向的元素。
示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// it指向mylist的第二个元素
list<int>::iterator it = mylist.begin() + 1;
// 删除it指向的元素,即2,并返回一个迭代器指向2之后的元素
list<int>::iterator itnew = mylist.erase(it);
cout << "\n删除元素后返回的迭代器itnew指向的元素为:" << *itnew;
cout << "\n使用erase删除元素后:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
删除元素后返回的迭代器itnew指向的元素为:3
使用erase删除元素后:1 3 4
用法二:list.erase(iterator1,iterator2)
这种用法会删除迭代器iterator1指向的元素到iterator2指向元素之间的元素,包括iterator1指向的元素但不包括iterator2指向的元素,即擦除[iterator1,iterator2)。
示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// it1指向mylist的第二个元素
list<int>::iterator it1 = mylist.begin() + 1;
// it2指向mylist的最后一个元素后一个位置
list<int>::iterator it2 = mylist.end();
// 删除[it1,it2)之间的元素,即删除2,3,4
mylist.erase(it1, it2);
cout << "\n使用erase删除元素后:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
使用erase删除元素后:1
(14) clear()——清空元素
clear的作用就是清空list中的所有元素
清空list中所有元素,并且list的大小变为0。使用
clear()
方法。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// 清除mylist中所有元素
mylist.clear();
cout << "\n使用erase清空元素后mylist.size() =" << mylist.size();
cout << "\n使用erase清空元素后:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
使用erase清空元素后mylist.size() =0
使用erase清空元素后:
(15) swap()——交换元素
❤swap的作用就是交换两个list的元素❤
交换两个list的元素,使用
swap()
方法,list1.swap(list2)
,两个list存储的元素类型必须相同,元素个数可以不同。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist1{1, 11, 111, 1111};
list<int> mylist2{2, 22, 222};
cout << "初始化后的mylist1为:";
for (auto num : mylist1) {
cout << num << " ";
}
cout << "\n初始化后的mylist1为:";
for (auto num : mylist2) {
cout << num << " ";
}
// 交换mylist1和mylist2的元素
mylist1.swap(mylist2);
cout << "\n使用swap交换元素后mylist1:";
for (auto num : mylist1) {
cout << num << " ";
}
cout << "\n使用swap交换元素后mylist2:";
for (auto num : mylist2) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist1为:1 11 111 1111
初始化后的mylist1为:2 22 222
使用swap交换元素后mylist1:2 22 222
使用swap交换元素后mylist2:1 11 111 1111
(16) emplace()——插入元素 【C++11】
向list中添加元素,使用
emplace(iterator,value)
方法,作用是向iterator迭代器指向元素的前边添加一个元素value。返回一个迭代器,指向新添加的元素。
emplace()方法是C++11引入的新方法,用于在容器中就地构造元素。它接受构造元素所需的参数,并在容器中的适当位置构造新元素,而不需要显式地创建临时对象。这样可以提高性能,避免了不必要的复制或移动操作。
示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist1为:";
for (auto num : mylist) {
cout << num << " ";
}
// it指向mylist第二个元素,即2
list<int>::iterator it = ++mylist.begin();
// 向it指向元素(2)前插入元素10,并返回指向10的迭代器
list<int>::iterator it1 = mylist.emplace(it, 10);
cout << "\n第一次插入后返回的迭代器it1指向元素为:" << *it1;
// 向it1指向元素(10)前插入元素20,并返回指向20的迭代器
list<int>::iterator it2 = mylist.emplace(it1, 20);
cout << "\n第二次插入后返回的迭代器it2指向元素为:" << *it2;
// 向mylist尾部插入元素30
list<int>::iterator it3 = mylist.emplace(mylist.end(), 30);
cout << "\n第三次插入后返回的迭代器it3指向元素为:" << *it3;
cout << "\n三次插入元素后,mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist1为:1 2 3 4
第一次插入后返回的迭代器it1指向元素为:10
第二次插入后返回的迭代器it2指向元素为:20
第三次插入后返回的迭代器it3指向元素为:30
三次插入元素后,mylist为:1 20 10 2 3 4 30
emplace和insert的区别:
emplace和insert插入元素最大的区别就是emplace不会产生不必要的变量,使用insert插入元素时,需要申请内存空间创建临时对象,而申请内存空间就需要消耗一定时间;而使用emplace插入元素时,直接在原来容器的内存空间上 ,调用构造函数,不需要额外申请内存空间,就节省了很多时间,效率较高。
(17) emplace_back()——在list尾部插入元素 【C++11】
在容器尾部生成一个元素。和 push_back() 的区别是,该函数直接在容器尾部构造元素,省去了复制移动元素的过程。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// 在list尾部插入一个元素10
mylist.emplace_back(10);
cout << "\n尾部插入一个元素后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
尾部插入一个元素后的mylist为:1 2 3 4 10
(18)emplace_front()——在list头部插入元素 【C++11】
在容器头部生成一个元素。和 push_front() 的区别是,该函数直接在容器头部构造元素,省去了复制移动元素的过程。示例如下:
💻示例代码💻
#include <list>
#include <iostream>
using std::cout;
using std::list;
using std::endl;
int main() {
list<int> mylist{1, 2, 3, 4};
cout << "初始化后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
// 在list头部插入一个元素10
mylist.emplace_front(10);
cout << "\n头部插入一个元素后的mylist为:";
for (auto num : mylist) {
cout << num << " ";
}
}
📄输出📄
初始化后的mylist为:1 2 3 4
头部插入一个元素后的mylist为:10 1 2 3 4
(19) merge()——合并list
将两个已排序的列表合并成一个有序的列表。merge()方法将另一个列表的元素插入到调用方法的列表中,并保持排序顺序。示例如下:
注意:merge()方法只能用于已排序的list。如果list未排序,则合并的结果将是不正确的。
用法一:list.merge(list2)
这种方式采用默认的比较函数
💻示例代码💻
#include <iostream>
#include <list>
using namespace std;
int main() {
std::list<int> list1 = {1, 3, 5};
std::list<int> list2 = {2, 4, 6};
cout << "初始化后的list1为:";
for (auto num : list1) {
cout << num << " ";
}
std::cout << std::endl;
cout << "初始化后的list2为:";
for (auto num : list2) {
cout << num << " ";
}
std::cout << std::endl;
// 将 list2 合并到 list1 中
list1.merge(list2);
// 输出合并后的列表
cout << "合并后的list1为:";
for (const auto& element : list1) {
std::cout << element << " ";
}
std::cout << std::endl;
return 0;
}
📄输出📄
初始化后的list1为:1 3 5
初始化后的list2为:2 4 6
合并后的list1为:1 2 3 4 5 6
用法二:list.merge(list2, compareFunction)
这种方式采用自定义的比较函数来合并两个list,compareFunction为自定义的比较函数,示例如下:示例中自定义了一个比较函数,它按照元素模5之后的大小进行比较。
💻示例代码💻
#include <iostream>
#include <list>
using namespace std;
bool customCompare(int x, int y) {
return x % 5 < y % 5;
}
int main() {
list<int> list1 = {3, 7, 8, 10, 21};
list<int> list2 = {5, 6, 9, 13, 18};
cout << "初始化后的list1为:";
for (auto num : list1) {
cout << num << " ";
}
std::cout << std::endl;
cout << "初始化后的list2为:";
for (auto num : list2) {
cout << num << " ";
}
std::cout << std::endl;
// 合并两个列表
list1.merge(list2, customCompare);
// 输出排序后的结果
cout << "合并后的list1为:";
for (int i : list1) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
📄输出📄
初始化后的list1为:3 7 8 10 21
初始化后的list2为:5 6 9 13 18
合并后的list1为:5 6 3 7 8 10 21 9 13 18
(20) splice()——从另一个list中移动元素
splice 方法用于将另一个 std::list 的元素插入到当前列表的指定位置。示例如下:
splice共有四种形式,分别为:
splice(iterator_pos, otherList)
: 将otherList中的所有元素移动到iterator_pos指向元素之前splice(iterator_pos, otherList, iter1)
: 从 otherList转移 iter1 指向的元素到当前list。元素被插入到 iterator_pos指向的元素之前。splice(iterator_pos, otherList, iter_start, iter_end)
: 从 otherList转移范围 [iter_start, iter_end) 中的元素到 当前列表。元素被插入到 iterator_pos指向的元素之前。
注意:
1. splice 操作不会进行元素的复制或移动,只是修改指针连接,因此效率较高。
2. 在 splice 操作后,被移动的元素将不再属于原始列表。
3. splice 操作后,原始列表和插入列表的大小会相应改变。
4. 插入操作的时间复杂度为 O(1)
💻示例代码💻
#include <iostream>
#include <list>
int main() {
std::list<int> list1 = {1, 2, 3, 4, 5};
std::list<int> list2 = {10, 20, 30};
std::list<int> list3 = {1, 2, 3, 4, 5};
std::list<int> list4 = {10, 20, 30};
std::list<int> list5 = {1, 2, 3, 4, 5};
std::list<int> list6 = {10, 20, 30};
/*
用法一 : splice(iterator_pos, otherList)
*/
// 将list2中所有元素插入到list1的第一个位置
list1.splice(list1.begin(), list2);
// 输出结果
std::cout<< "转移list2元素到list1之后的list1: ";
for (int i : list1) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout<< "转移list2元素到list1之后的list1: ";
for (int i : list2) {
std::cout << i << " ";
}
std::cout << std::endl;
/*
用法二:splice(iterator_pos, otherList, iter1)
*/
auto it = list3.begin();
// 将迭代器向后移动两个位置,指向第三个元素
std::advance(it, 2);
// 将list4的第一个元素(10)插入到list3的第三个位置
list3.splice(it, list4, list4.begin());
// 输出结果
std::cout<< "转移list4元素到list3之后的list3: ";
for (int i : list3) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout<< "转移list4元素到list3之后的list4: ";
for (int i : list4) {
std::cout << i << " ";
}
std::cout << std::endl;
/*
用法三:splice(iterator_pos, otherList, iter_start, iter_end)
*/
// 将list5中第二个到第四个元素移动到list6的末尾
auto first = list5.begin();
std::advance(first, 1);
auto last = list5.begin();
std::advance(last, 4);
list6.splice(list6.end(), list5, first, last);
// 输出结果
std::cout<< "转移list5元素到list6之后的list5: ";
for (int i : list5) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout<< "转移list5元素到list6之后的list6: ";
for (int i : list6) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
📄初始化的值📄
std::list<int> list1 = {1, 2, 3, 4, 5};
std::list<int> list2 = {10, 20, 30};
std::list<int> list3 = {1, 2, 3, 4, 5};
std::list<int> list4 = {10, 20, 30};
std::list<int> list5 = {1, 2, 3, 4, 5};
std::list<int> list6 = {10, 20, 30};
📄输出📄
转移list2元素到list1之后的list1: 10 20 30 1 2 3 4 5
转移list2元素到list1之后的list1:
转移list4元素到list3之后的list3: 1 2 10 3 4 5
转移list4元素到list3之后的list4: 20 30
转移list5元素到list6之后的list5: 1 5
转移list5元素到list6之后的list6: 10 20 30 2 3 4
(21) remove()——移除特定值的元素
std::list 的 remove 方法用于从列表中移除与指定值相等的元素。示例如下:
💻示例代码💻
#include <iostream>
#include <list>
int main() {
std::list<int> mylist {1, 2, 3, 4, 5};
// 移除列表中所有值为2的元素
mylist.remove(2);
std::cout << "移除之后的mylist: ";
for (const auto& element : mylist) {
std::cout << element << " ";
}
std::cout << std::endl;
return 0;
}
📄输出📄
移除之后的mylist: 1 3 4 5
(21) remove_if()——移除满足特定标准的元素
使用方式:remove_if(func)
使用 remove_if 方法可以从 mylist 中移除所有满足 函数func的元素,下边的例子中定义了一个函数isEven(),判断一个数字是否为偶数。示例如下:
💻示例代码💻
#include <iostream>
#include <list>
bool isEven(int n) {
return n % 2 == 0;
}
int main() {
std::list<int> mylist {1, 2, 3, 4, 5};
// 移除列表中所有满足 isEven 的元素(偶数)
mylist.remove_if(isEven);
std::cout << "移除之后的mylist: ";
for (const auto& element : mylist) {
std::cout << element << " ";
}
std::cout << std::endl;
return 0;
}
📄输出📄
移除之后的mylist: 1 3 5
(22) reverse()——将该链表的所有元素的顺序反转 【C++11】
reverse()方法用于反转链表中元素的顺序,即将链表中的第一个元素变为最后一个元素,第二个元素变为倒数第二个元素,以此类推。示例如下:
💻示例代码💻
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {1, 2, 3, 4, 5};
std::cout << "初始化list为: ";
for (const auto& element : myList) {
std::cout << element << " ";
}
std::cout << std::endl;
myList.reverse();
std::cout << "Reversed后的list为: ";
for (const auto& element : myList) {
std::cout << element << " ";
}
std::cout << std::endl;
return 0;
}
📄输出📄
初始化list为: 1 2 3 4 5
Reversed后的list为: 5 4 3 2 1
(23) unique()——删除连续的重复元素
unique()方法用于移除链表中相邻且重复的元素,仅保留一个副本。示例如下:
💻示例代码💻
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {1, 2, 2, 3, 3, 4, 5, 5, 5};
std::cout << "初始化后的list为: ";
for (auto i : myList) {
std::cout << i << " ";
}
std::cout << std::endl;
myList.unique();
std::cout << "执行unique后的list为: ";
for (auto i : myList) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
📄输出📄
初始化后的list为: 1 2 2 3 3 4 5 5 5
执行unique后的list为: 1 2 3 4 5
(24) sort()——对元素进行排序
sort()方法用于对链表中的元素进行排序。默认情况下,它按升序对元素进行排序,使用元素类型的 < 运算符进行比较。示例如下:
💻示例代码💻
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {5, 3, 2, 4, 1};
std::cout << "初始化后的list为 ";
for (auto i : myList) {
std::cout << i << " ";
}
std::cout << std::endl;
myList.sort();
std::cout << "排序后的list为: ";
for (auto i : myList) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
📄输出📄
初始化后的list为 5 3 2 4 1
排序后的list为: 1 2 3 4 5
(25) assign()——将值赋给容器
assign()方法用于将链表中的元素替换为新的元素序列。它可以接受不同形式的参数,提供了两种重载形式。
- 第一种形式接受迭代器范围作为参数,用于将另一个容器或数组中的元素复制到链表中。它会将链表清空,并将指定范围内的元素复制到链表中。
void assign(InputIterator first, InputIterator last);
- 第二种形式接受一个元素数量和一个值作为参数,用于将指定数量的相同值的元素分配给链表。它会将链表清空,并将指定数量的元素赋值为指定的值。
void assign(size_type count, const T& value);
示例如下:
💻示例代码💻
#include <iostream>
#include <vector>
#include <list>
int main() {
std::list<int> myList;
// 使用迭代器范围进行分配
std::vector<int> numbers = {1, 2, 3, 4, 5};
myList.assign(numbers.begin(), numbers.end());
std::cout << "第一次执行assign之后的list为: ";
for (auto i : myList) {
std::cout << i << " ";
}
std::cout << std::endl;
// 使用元素数量和值进行分配
myList.assign(3, 100);
std::cout << "第二次执行assign之后的list为: ";
for (auto i : myList) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
📄输出📄
第一次执行assign之后的list为: 1 2 3 4 5
第二次执行assign之后的list为: 100 100 100
结语:
本文详细总结了list容器的一些方法,包括list使用,list初始化,list迭代器,list所有操作。
list begin(); list end(); list rbegin(); list rend(); list cbegin(); list cend(); list crbegin(); list crend(); list size(); list max_size(); list resize(n); list empty(); list push_back(); list push_front() ;list pop_front() ;list pop_back() ;list at(i);list front(); list back(); list assign(); list insert(); list erase(); list clear(); list swap(); list emplace(); list emplace_front();list emplace_back(); list clear() list swap() list merge() list splice() list remove() remove_if() list reverse() list unique() list sort()
希望大家看完后能对list的掌握更加深刻。
欢迎关注🔎点赞👍收藏⭐️留言📝
获取源码,了解更多编程知识,请点击下方名片