十三、list 类

Ⅰ . list 的介绍和使用

01 初识 list

我们已经学习过 string 和 vector 了,想必大家已经掌握了查文档的能力

现在我们去学习如何使用 list ,最好仍然打开文档去学习

list - C++ Reference

① list 是一个顺序容器

允许在任意位置进行 O(1) 插入和删除的顺序容器,并提供双向迭代器

② list 底层是双向链表

双向链表中每个元素存储在互不相关的独立结点中,在结点中通过两个指针指向其前后元素

③ list 与 forward_list 非常相似

最大的不同就是 forward_list 是单链表,只能向前迭代

④ 与其他序列式容器相比(array,vector,deque)

list 通常在任意位置进行插入、删除元素的效率更高,因为是 O(1)

list 和 forward_list 最大的缺陷是不支持随机位置的随机访问 举个例子:

如果要访问 list 中的第六个元素,必须从已知位置(如头部或尾部)迭代到该位置

在这段位置上迭代需要线性时间的时间开销,同时,list 还需要一些额外空间

以保存每个结点的相关联信息

02 创建 list

代码实现:

cpp 复制代码
#include<iostream>
#include<list>
using namespace std;

int main()
{
	list<int> l;

	return 0;
}

Ⅱ . list 的修改操作

01 修改操作的函数

02 push_back

在 list 尾部插入值为 val 的元素

代码实现:

cpp 复制代码
#include<iostream>
#include<list>
using namespace std;

int main()
{
	list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	l.push_back(4);

	return 0;
}

我们现在来打印一下

首先思考一个问题,还能使用下标 + 方括号的方式遍历嘛?

不行 因为 list 是链表,是通过指针连接的,所以不支持随机访问

而 string 和 vector 可以,因为它们的物理结构是连续的

迭代器遍历:

cpp 复制代码
#include<iostream>
#include<list>
using namespace std;

int main()
{
	list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	l.push_back(4);

	// 迭代器
	list<int>::iterator it = l.begin();
	while (it != l.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	return 0;
}

运行结果如下:

范围 for 就更简单了:

cpp 复制代码
	// 范围for
	for (auto e : l)
		cout << e << " ";
	cout << endl;

如果我们想倒着遍历,我们可以使用反向迭代器

使用 rbegin() 和 rend()

反向迭代器:

cpp 复制代码
	// 反向迭代器
	list<int>::reverse_iterator rit = l.rbegin();
	while (rit != l.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

运行结果如下:

03 push_front

在 list 头部插入值为 val 的元素

代码实现:

cpp 复制代码
void list_test2()
{
	list<int> l;
	l.push_front(1);
	l.push_front(2);
	l.push_front(3);
	l.push_front(4);

	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

04 pop_back

删除 list 中的最后一个元素

cpp 复制代码
void list_test3()
{
	list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	l.push_back(4);

	cout << "删除前:";
	for (auto e : l)
		cout << e << " ";
	cout << endl;

	l.pop_back();
	cout << "删除后:";
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

如果表内没有元素,进行删除操作,会触发断言

05 pop_front

删除 list 中的第一个元素

cpp 复制代码
void list_test4()
{
	list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	l.push_back(4);

	cout << "删除前:";
	for (auto e : l)
		cout << e << " ";
	cout << endl;

	l.pop_front();
	cout << "删除后:";
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

06 insert

在上一节讲解 vector 实现的时候,我们对迭代器失效的问题进行了简单探讨

这里 list 的 insert 同样会涉及迭代器失效的问题,我们在模拟实现的时候再进行探讨

07 clear

清空 list 中的有效元素,使容器大小的 size 变为 0

代码演示:

cpp 复制代码
void list_test5()
{
	list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	l.push_back(4);

	cout << "清空前:";
	for (auto e : l)
		cout << e << " ";
	cout << endl;

	l.clear();
	cout << "清空后:";
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

08 erase

代码演示:

cpp 复制代码
void list_test6()
{
	list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	l.push_back(4);
	for (auto e : l)
		cout << e << " ";
	cout << endl;

	list<int>::iterator it = find(l.begin(), l.end(), 4);
	if (it != l.end())
	{
		l.erase(it);
	}
	else
	{
		cout << "没找到";
	}
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

Ⅲ . list 容量操作

01 size 返回有效结点个数

代码演示:

cpp 复制代码
void list_test7() 
{
	list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	l.push_back(4);
	for (auto e : l) 
		cout << e << " "; 
	cout << endl;

	cout << "有效节点个数:";
	cout << l.size() << endl;
}

运行结果如下:

02 empty 检测容器是否为空

empty 是用来检测容器是否为空的,如果为空则返回 true,否则返回 false。

代码演示:

cpp 复制代码
void list_test8()
{
	list<int> l;
	l.empty() == true ? cout << "为空" : cout << "不为空";
}

运行结果如下:

03 resize 调整容器大小

list 中的 resize 和之前的 resize 的 "扩容" 有点不一样,它没有容量。

这里的 resize 是调整容器的大小,使其包含 ​ 个元素。

代码演示:

cpp 复制代码
void list_test9()
{
	list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	l.push_back(4);
	for (auto e : l)
		cout << e << " ";
	cout << endl;

	l.resize(10, 5);
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

Ⅳ . list 的其他操作

01 reverse 逆置

代码演示:

cpp 复制代码
void list_test10()
{
	list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	l.push_back(4);
	for (auto e : l)
		cout << e << " ";
	cout << endl;

	l.reverse();
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

02 sort 排序

代码演示:

cpp 复制代码
void list_test11()
{
	list<int> l;
	l.push_back(4);
	l.push_back(2);
	l.push_back(6);
	l.push_back(1);
	for (auto e : l)
		cout << e << " ";
	cout << endl;

	l.sort();
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

03 unique 去重

去重之前是有要求的,去重之前一定要先排序,如果不排序可能会去不干净

代码演示:

cpp 复制代码
void list_test12()
{
	list<int> l;
	l.push_back(2);
	l.push_back(1);
	l.push_back(2);
	l.push_back(1);
	for (auto e : l)
		cout << e << " ";
	cout << endl;

	l.sort();
	cout << "去重后:";
	l.unique();
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

如果不排序,会导致去不干净:

cpp 复制代码
void list_test12()
{
	list<int> l;
	l.push_back(2);
	l.push_back(1);
	l.push_back(2);
	l.push_back(1);
	for (auto e : l)
		cout << e << " ";
	cout << endl;

	//l.sort();
	cout << "去重后:";
	l.unique();
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

04 remove

remove 只需要给一个元素的值,它就可以自己找自己删

代码演示:

cpp 复制代码
void list_test13() 
{
	list<int> l;
	l.push_back(10);
	l.push_back(20);
	l.push_back(30);
	l.push_back(40);
	for (auto e : l) 
		cout << e << " "; 
	cout << endl;

	// 如果删一个存在的元素
	l.remove(10);
	for (auto e : l) 
		cout << e << " "; 
	cout << endl;

	// 如果待删元素不存在
	l.remove(0);
	for (auto e : l) 
		cout << e << " "; 
	cout << endl;
}

运行结果如下:

05 splice 接合

简单来说就是把一个链表转移到另一个链表中

代码演示:

cpp 复制代码
void list_test14()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	cout << "l1:";
	for (auto e : l1)
		cout << e << " ";
	cout << endl;

	list<int> l2;
	l2.push_back(10);
	l2.push_back(20);
	l2.push_back(30);
	cout << "l2:";
	for (auto e : l2)
		cout << e << " ";
	cout << endl;

	list<int>::iterator pos = l1.begin();
	// 把l2的内容接到l1的begin()前面
	l1.splice(pos, l2);
	cout << "接合后";
	for (auto e : l1)
		cout << e << " ";
	cout << endl;
}

运行结果如下:

相关推荐
‘’林花谢了春红‘’4 小时前
C++ list (链表)容器
c++·链表·list
机器视觉知识推荐、就业指导5 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
阿龟在奔跑7 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
Yang.997 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
熬夜学编程的小王7 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
zz40_7 小时前
C++自己写类 和 运算符重载函数
c++
六月的翅膀8 小时前
C++:实例访问静态成员函数和类访问静态成员函数有什么区别
开发语言·c++
liujjjiyun8 小时前
小R的随机播放顺序
数据结构·c++·算法
¥ 多多¥8 小时前
c++中mystring运算符重载
开发语言·c++·算法