(笔记)List

一、List的介绍和使用

1.List的介绍

1.1 list是可以在任意常数范围内插入和删除的序列式容器,并且该容器可以前后双向迭代。

1.2 list底层是双向链表结构,双向链表中每个元素都储存在互不相关的独立节点中,在节点中通过指针指向前其前一个元素和后一个元素。

1.3 list和forward_list非常相似,不同的是forward_list是单链表,只能向前迭代,能让其更简单高效。

1.4 与其他容器(array,vector,deque)相比,list通常在任意位置插入,移除元素的执行效率更好。

1.5 与其他容器相比,list和forward_list最大的缺陷是不能支持任意位置的随机访问,比如:要访问list的第六个位置的元素,必须从已知的位置迭代到该位置,在这段位置迭代需要线性的的时间开销,list还需要一些额外空间开销,以保存每个节点的关联信息

2.List的使用

2.1 list的构造

|-----------------------------------------------------------|---------------------------|
| 构造函数 | 接口说明 |
| list(size_type n,const value_type& val=value_type()) | 构造的list包括n个位val的值 |
| list() | 构造空的list |
| list(const list& x) | 拷贝构造函数 |
| list(InputIterator first,InputIterator last) | 用[fisrt,last)区间的元素构造list |

构造函数的使用:

cpp 复制代码
//list的构造
void test1()
{
	list<int> l1;		//构造空的list
	list<int> l2(5, 10);//用5个10来构造list
	list<int> l3(l2.begin(), l2.end());	//用l2的begin和end迭代器构造list
	list<int> l4(l3);	//拷贝构造

	//有数组的迭代器构造list
	int array[] = { 10,20,30,40,50 };
	list<int> l5(array, array + (sizeof(array) / sizeof(int)));

	//用迭代器的方式打印
	list<int>::iterator it = l5.begin();
	while (it != l5.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	//直接用列表初始化构造list
	list<int> l6{ 1,2,3,4,5,6 };

	//用范围for的方式进行打印
	for (auto e : l6)
	{
		cout << e << " ";
	}
	cout << endl;

}

运行结果:

cpp 复制代码
10 20 30 40 50
1 2 3 4 5 6

2.2 list iterator的使用

此处,可以吧iterator理解成为一个指针,指向list的一个节点

|-----------------|------------------------------|
| 函数声明 | 接口说明 |
| begin+end | 返回第一个节点的迭代器和最后一个位置的下一个节点的迭代器 |
| rbegin+rend | 返回最后一个节点的迭代器和第一个节点的前一个迭代器 |

迭代器的使用:

cpp 复制代码
//list的迭代器的使用
void test2()
{
	list<int> l1{ 1,2,3,4,5,6,7,8 };
	list<int>::iterator it = l1.begin();
	//auto it=l1.begin();
	//用迭代器打印l1
	while (it != l1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	//用范围for打印l1
	//范围for的底层也是迭代器
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;

	//反向迭代器的使用
	list<int>::reverse_iterator rit = l1.rbegin();
	while (rit != l1.rend())
	{
		cout << *rit << " ";
		rit++;
	}
	cout << endl;


}

运行结果:

cpp 复制代码
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8
8 7 6 5 4 3 2 1

begin和end为正向迭代器,对迭代器进行++操作,迭代器向后移动;

rbegin和rend为反向迭代器,对迭代器进行++操作,迭代器向前移动;

2.3 list capacity

|--------------|----------------------------------|
| 函数声明 | 接口说明 |
| empty | 检测list是否为空,是空则返回true,不是空则返回false |
| size | 返回list中有效节点的个数 |
| max_size | 返回列表容器可以存储最大元素的个数 |

capacity的使用:

cpp 复制代码
void test3()
{
	list<int> l1(6, 2);
	cout << l1.empty() << endl;
	cout << l1.size() << endl;
	cout << l1.max_size() << endl;
}

运行结果:

cpp 复制代码
0
6
768614336404564650

2.4 list element access

|-----------|-------------------|
| 函数声明 | 接口说明 |
| front | 返回list第一个节点的值的引用 |
| back | 返回list最后一个节点的值的引用 |

element access的使用:

cpp 复制代码
//element access
void test4()
{
	list<string> l1{ "123","234","345","456","567" };
	cout << l1.front() << endl;
	cout << l1.back() << endl;
	l1.front() = "111";
	l1.back() = "777";
	cout << l1.front() << endl;
	cout << l1.back() << endl;
}

运行结果:

cpp 复制代码
123
567
111
777

2.5 list modifiers

|------------------------------------------------------------|-----------------------|
| 函数声明 | 接口说明 |
| push_front(const value_type& val) | 在list首元素前插入值为val的元素 |
| pop_front() | 删除list的第一个元素 |
| push_back(const value_type& val) | 在list尾部插入值为val的元素 |
| pop_back() | 删除list尾部的元素 |
| insert(const_iterator position,const value_type& val) | 在position位置插入值为val的元素 |
| erase(const_iterator position) | 删除position位置的元素 |
| swap(list& x) | 交换两个list的元素 |
| clear() | 清空list中的有效元素 |

push_front、push_back、pop_front、pop_back的使用:

cpp 复制代码
template<class T>
void Printlist(const list<T>& l)
{
	for (auto e : l)
	{
		cout << e << " ";
	}
	cout << endl;
}
//push_front、pop_front、push_back、pop_back
void test5()
{
	list<int> l1;
	l1.push_front(1);
	l1.push_front(2);
	l1.push_front(3);
	l1.push_front(4);
	Printlist(l1);
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	Printlist(l1);
	l1.pop_front();
	l1.pop_front();
	l1.pop_back();
	l1.pop_back();
	Printlist(l1);
}

运行结果:

cpp 复制代码
4 3 2 1
4 3 2 1 1 2 3 4
2 1 1 2

insert、erase的使用:

cpp 复制代码
//insert、earse
void test6()
{
	list<int> l1{ 1,2,3,4 };
	//获取l1第二个元素的位置
	list<int>::iterator pos = ++l1.begin();
	cout << *pos << endl;
	//在pos位置之前插入值为5的元素
	l1.insert(pos, 5);
	Printlist(l1);
	//此时的pos位置还是指向2的位置
	cout << *pos << endl;
	//在pos位置前插入6个值为6的元素
	//insert(const_iterator position,size_t n,value_type& val)
	l1.insert(pos, 6, 6);
	Printlist(l1);
	//在pos位置插入一段迭代器指向的内容
	int array[] = { 7,8,9 };
	l1.insert(pos, array, array + (sizeof(array) / sizeof(int)));
	Printlist(l1);
	//删除pos位置上的值
	l1.erase(pos);
	Printlist(l1);
	//删除一段迭代器区间的值
	l1.erase(++l1.begin(), --l1.end());
	Printlist(l1);
}

运行结果:

cpp 复制代码
2
1 5 2 3 4
2
1 5 6 6 6 6 6 6 2 3 4
1 5 6 6 6 6 6 6 7 8 9 2 3 4
1 5 6 6 6 6 6 6 7 8 9 3 4
1 4

swap和clear的使用:

cpp 复制代码
//swap和clear
void test7()
{
	list<int> l1{ 1,2,3,4 };
	list<int> l2;
	Printlist(l1);
	Printlist(l2);
	//交换l1和l2的元素
	l1.swap(l2);
	Printlist(l1);
	Printlist(l2);
	//清空l2
	l2.clear();
	Printlist(l2);
}

运行结果:

cpp 复制代码
1 2 3 4


1 2 3 4

2.6 list的迭代器失效

list底层结构为带头双向循环链表,因此在list中插入是不会导致迭代器失效的,只有在删除时才会失效,而且失效的只是被删除的节点处的迭代器,其他位置的迭代器不会被影响。

cpp 复制代码
void test8()
{
	list<int> l1{ 1,2,3,4,5,6,7 };
	list<int>::iterator it = l1.begin();
	//while (it != l1.end())
	//{
	//	//当删除迭代器it位置上的元素后,it就已经失效了,接下来对it进行操作会导致报错
	//	l1.erase(it);
	//	it++;
	//}
	while (it != l1.end())
	{
		//因此要对it进行重新赋值
		it = l1.erase(it);
	}
}

三、list和vector的比较

|-------|------------------------------------------------------|-------------------------------------|
| | vector | list |
| 底层结构 | 动态顺序表,一段连续的空间 | 带头结点的双向循环链表 |
| 随机访问 | 支持随机访问,访问数据的效率为O(1) | 不支持随机访问,访问某个数据的效率为O(N) |
| 插入和删除 | 任意位置的插入和删除效率低,需要移动数据,效率为O(N),插入时可能会扩容,存在扩容的情况的话效率会更低 | 任意位置插入和删除效率高,不需要搬移数据 |
| 空间利用率 | 底层为连续空间,不存在空间碎片,空间利用率高,缓存利用率高 | 底层节点动态开辟,小节点容易造成空间碎片,空间利用率低,缓存利用率低 |
| 迭代器 | 原生态指针 | 对原生态指针进行封装 |
| 迭代器失效 | 插入需要扩容时迭代器会失效,删除任意位置元素时迭代器也会默认失效,删除时当前位置和后面的迭代器都会失效 | 删除元素时迭代器会失效,但只是当前迭代器失效,其他位置的迭代器不受影响 |
| 使用场景 | 需要高速缓存,支持随机访问,不需要考虑插入和删除效率的场景 | 大量插入和删除,不考虑随机访问的场景 |

相关推荐
green_pine_1 小时前
Vue3学习笔记2——路由守卫
前端·vue.js·笔记·学习
DIY机器人工房5 小时前
[3-2]GPIO输入 江协科技学习笔记(17个知识点)
笔记·科技·学习
诗句藏于尽头7 小时前
小程序滚动条隐藏(uniapp版本)
笔记·小程序·uni-app
Small踢倒coffee_氕氘氚7 小时前
Python语句类型与格式规范研究
经验分享·笔记·灌灌灌灌
DIY机器人工房7 小时前
[5-1]EXTI外部中断 江协科技学习笔记(32个知识点)
笔记·科技·stm32·单片机·嵌入式硬件·学习
不太可爱的叶某人10 小时前
【学习笔记】深入理解Java虚拟机学习笔记——第1章 走进Java
java·jvm·笔记·学习
杨浦老苏13 小时前
Nanote:极简Markdown笔记应用
笔记·docker·markdown·群晖
汇能感知13 小时前
光谱相机如何提升目标检测与识别精度
经验分享·笔记·科技
踢足球的程序员·14 小时前
GAMES202-高质量实时渲染(Assignment 2)
笔记·学习·图形渲染