文章目录

  • 零.前言
  • 1.list的介绍
  • 2.创建变量
  • 3.遍历
  • (1)迭代器遍历
  • (2)范围for遍历
  • 4.list的大小
  • 5.插入删除
  • (1)头尾插删
  • (2)insert与erase
  • 6.交换,排序与清除
  • (1)排序
  • (2)交换
  • (3)清除
  • 7.总结

零.前言

学习了vector与string我们可以知道,所谓的STL就是将字符串,数组等数据结构进行严密地封装,方便我们直接使用而不需要进行临时创建,本节将介绍STL中的list,该类是对双向带头循环链表的使用。

1.list的介绍

list表示的是一个双向带头循环链表,允许在常数范围内的任意位置进行插入和删除,且前后可以进行双向迭代。其缺陷和链表一样就是不能支持随机访问(下标访问),但是在任意位置进行插入的效率更高。

2.创建变量

在创建变量之前别忘记包含list的头文件。

list<int> l1;//创建一个空对象
	list<int> l2(3, 1);//创建一个包含3个1的对象
	list<int> l3(l2);//拷贝构造
	list<int> l4(l3.begin()++, l3.end()--);//在l3.begin()与l3.end()之间创造对象

注意由于l3是链表,因此不能将l3.begin()进行+1等操作。但是可以进行++,–的操作

3.遍历

与list和vector不同,list的遍历不能使用下标遍历,因为他是链表。
但我们可以使用迭代器进行遍历,这里的迭代器是双向迭代器,而不是像list和vector一样是随机迭代器。
双向迭代器的构造使其可以进行++等访问操作,在底层实际上就是操作符重载。

(1)迭代器遍历

list<int>::iterator it = l3.begin();
	while (it != l3.end())
	{
		*it += 1;
		cout << *it<<" ";
		it++;
	}

同时也支持rbegin与rend,这里不予演示了。

(2)范围for遍历

for (auto& e : l3)
	{
		cout << e << " ";
	}

使用范围for时,其底层也是迭代器,像vector一样传链表名即可。将迭代器类型改为reverse_iterator即可使用反向迭代器。反向迭代器在string详解中已经介绍过了。

4.list的大小

链表是插入元素,不需要进行提前扩容,因此没有reserve操作。我们可以使用empty来判空,使用size返回大小。

cout << l1.empty() << endl;
	cout << l3.size() << endl;

swift list遍历 stl list遍历_迭代器

5.插入删除

(1)头尾插删

我们可以使用push_back,push_front,pop_back,pop_front等进行插入和删除。

l1.push_back(1);
	l1.push_back(2);
	l1.push_back(5);
	l1.push_back(3);
	l1.push_back(4);
	l1.push_front(6);
	l1.push_front(8);
	l1.pop_front();
	l1.pop_back();
	for (auto& e : l1)
	{
		cout << e << " ";
	}

swift list遍历 stl list遍历_swift list遍历_02

(2)insert与erase

insert使用:

auto pos = ++l1.begin();
	l1.insert(pos, 5);//在pos位置前加1个5
	l1.insert(pos, 3, 5);//在pos位置前加3个5
	l1.insert(pos, l3.begin(), l3.end());//将l3加到pos位置前
	for (auto& e : l1)
	{
		cout << e << " ";
	}

erase使用:

l1.erase(pos);//删除pos位置元素
	l1.erase(++l1.begin(), --l1.end());//删除中间内容

在使用erase时要注意迭代器失效问题(迭代器指向节点被删除)。

swift list遍历 stl list遍历_swift list遍历_03

6.交换,排序与清除

(1)排序

在vector中我们可以使用algorithm中的sort进行排序,而在list中只能使用list提供的sort,这是因为算法中的sort传参只能传随机迭代器,而list中是双向迭代器。
我们拿上方代码没erase的时候进行排序:

l1.sort();
	for (auto& e : l1)
	{
		cout << e << " ";
	}

swift list遍历 stl list遍历_循环链表_04


链表的排序效率过低,如果要排序尽量使用vector不要使用list。

(2)交换

将两个链表中内容进行交换的函数:

l1.swap(l3);

swift list遍历 stl list遍历_循环链表_05

(3)清除

清空链表中元素。

l1.clear();

swift list遍历 stl list遍历_循环链表_06

7.总结

list的使用与vector基本一致,但是底层的实现却大相径庭,要真正理解list我们还需要多去阅读STL的源代码,可以尝试着模拟实现一下list类。