STL中容器list -- 讲解超详细

大纲:

1. list容器的相关介绍

(1)list是 C++ 标准库<list>头文件中的双向链表容器,属于STL序列式容器的一种,用于存储有序的元素集合。

(2)list的底层:是一个双向循环双链表,每一个结点都包含数据,前向指针,后向指针;结点在内存中非连续存储(元素节点分散在内存中,通过指针连接,无需预留连续内存空间),所以增删元素仅需修改指针指向,无需移动其他元素(可频繁的插入/删除元素)

(3)list支持双向迭代,同时由于结点是动态申请和释放,不存在容量和大小的区别,也就没有reserve()和capacity()成员函数。

(4)list相对于string和vector新增了一些接口,如splice和merge,能实现高效转移和合并列表。

(5)list不支持通过下标访问元素。

2. 构造函数和析构函数

2.1 常用的构造函数

(1)无参构造

cpp 复制代码
list<int> l1;

(2)构造n个val

cpp 复制代码
list<int> l2(10, 1);//构造10个1
list<string> l3(10, "abcde");//构造10个字符串"abcde"

(3)拷贝构造函数

cpp 复制代码
list<string> l4(l3);

(4)迭代器构造

cpp 复制代码
list<string> l5(l3.begin(), l3.end());

(5)初始化列表构造

cpp 复制代码
list<int> l6({6,16,26,36,46,56,66});

2.2 析构函数

cpp 复制代码
~list();

注:后面模拟实现的时候,析构的方法具体分析

3. 修改容器内容的相关函数

3.1 push_front()

push_front:在list首元素前插入值为val的元素,所以打印是倒序。

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

	for (auto& e : l)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << l.size() << endl;
}

3.2 pop_front()

pop_front:删除list中第一个元素。

cpp 复制代码
void test02()
{
	list<int> l;
	l.push_front(13);
	l.push_front(28);
	l.push_front(33);
	l.push_front(41);
	l.push_front(52);

	l.pop_front();
	l.pop_front();

	for (auto& e : l)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << l.size() << endl;
}

注:相对于前面的vector容器,list的插入和删除数据更高效,不需要挪动数据,只需要更改指针指向即可!!!

3.3 insert()

insert:在pos位置中插入值为val的元素。

(1)第1种方式:

cpp 复制代码
// insert
list<int> l1 = { 10,20,30 };
list<int> l2 = { 60,70,90 };
l2.insert(--l2.end(), 66);
for (auto& e : l2)
{
	cout << e << " ";
}
cout << endl;//60 70 66 90

(2)第2种方式:

cpp 复制代码
// insert
list<int> l1 = { 10,20,30 };
list<int> l2 = { 60,70,90 };
l2.insert(++l2.begin(), l1.begin(), l1.end());
for (auto& e : l2)
{
	cout << e << " ";
}
cout << endl;//60 10 20 30 70 66 90

(3)第3种方式:

cpp 复制代码
l2.insert(--l2.end(), { 1,2,3,4,5 });
for (auto& e : l2)
{
	cout << e << " ";
}
cout << endl;//60 70 66 1 2 3 4 5 90

3.4 erase

erase:

(1)第1种方式:

删除指定位置的结点,这里需要注意前置--和后置--的区别,C++标准库只实现了前者;另外需要注意:end()不是最后一个结点;

cpp 复制代码
void test03()
{
	list<int> l({6,16,26,36,46,56,66});
	for (auto& e : l)
	{
		cout << e << " ";
	}
	cout << endl;
	l.erase(l.begin());//头删
	l.erase(--l.end());//尾删
	for (auto& e : l)
	{
		cout << e << " ";
	}
    //16 26 36 46 56
}

(2)第2种方式:

cpp 复制代码
l.erase(++l.begin(), --l.end());
for (auto& e : l)
{
	cout << e << " ";
}
cout << endl;//6 66

3.5 swap

直接实现两个链表的数据交换!!!

cpp 复制代码
void test04()
{
	list<int> l1({ 6,16,26,36,46,56,66 });
	list<int> l2({ 9,99,999 });
	for (auto& e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	l1.swap(l2);
	for (auto& e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
}

3.6 resize()

resize():强制将链表的元素个数(长度)调整为指定的目标值 n,调整逻辑分扩容和缩容两种情况,且操作是原地修改链表,不会返回新对象。

情况 1:n > 原长度(扩容)-- 尾部插入新节点

情况 2:n < 原长度(缩容)-- 尾部删除节点

cpp 复制代码
void test05()
{
	list<int> l1({ 6,16,26,36,46,56,66 });
	cout << l1.size() << endl;
	l1.resize(5);//7
	for (auto& e : l1)//缩容
	{
		cout << e << " ";
	}
	cout << endl;
    //6 16 26 36 46

	l1.resize(10, 1);//扩容
	for (auto& e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
    //6 16 26 36 46 1 1 1 1 1
}

3.7 clear

clear:清空list中的有效元素

cpp 复制代码
l1.clear();
for (auto& e : l1)
{
	cout << e << " ";
}
cout << endl;

4. 迭代器

4.1 begin() 和 end()

正向迭代器,链表第一个元素和尾后位置。

cpp 复制代码
list<int> l1({ 6,16,26,36,46,56,66 });
list<int>::iterator start = l1.begin();
list<int>::iterator finish = l1.end();

while (start != finish)
{
	cout << *start << " ";
	++start;
}
cout << endl;
//6,16,26,36,46,56,66

4.2 rbegin() 和 rend()

反向迭代器,链表最后一个元素和头前位置,这里的++rbegin,倒着往前移动指向。

cpp 复制代码
list<int>::reverse_iterator rstart = l1.rbegin();
list<int>::reverse_iterator rfinish = l1.rend();
while (rstart != rfinish)
{
	cout << *rstart << " ";
	++rstart;
}
cout << endl;

5. 容器访问相关函数

5.1 front() 和 back()

访问第一个元素和最后一个有效元素

cpp 复制代码
void test07()
{
	list<int> l1 = { 10,20,30,40,50 };
	cout << l1.front() << endl;//10
	cout << l1.back() << endl;//50
}

6. 操作容器的相关函数

6.1 splice()

splice:将元素从一个列表转移到另一个列表。

**注意:**这里的移动不是复制,移动数据后,原链表的数据会被移除。

这里和insert声明类似,这里就选择第二种方式说明:

(把lt2的200移动到lt1的30之前)

cpp 复制代码
void test07()
{
	list<int> lt1 = { 10, 20, 30 };
	list<int> lt2 = { 100, 200, 300 };
	printList(lt1, "移动前 lt1");
	printList(lt2, "移动前 lt2");
	cout << endl;
	list<int>::const_iterator ele_to_move = ++lt2.begin();
	lt1.splice(--lt1.end(), lt2, ele_to_move);
	printList(lt1, "移动后 lt1");
	printList(lt2, "移动后 lt2");
}

//移动前 lt1: 10 20 30
//移动前 lt2: 100 200 300

//移动后 lt1: 10 20 200 30
//移动后 lt2: 100 300

6.2 remove()

remove() -- 移除特定的数据

cpp 复制代码
void test08()
{
	int arr[] = { 17,89,7,14 };
	list<int> mylist(arr, arr + 4);
	printList(mylist, "移除前 mylist");

	mylist.remove(89);
	printList(mylist, "移除后 mylist");
}

6.3 unique()

unique() -- 移除连续的重复元素。功能特性和标准的搜索二叉树和标准的AVL数类似,后面说。

cpp 复制代码
void test09()
{
	list<int> mylist({ 17,89,7,14,99,66,66,6,2,17,17 });
	printList(mylist, "移除前 mylist");

	mylist.unique();
	printList(mylist, "移除后 mylist");
}

//移除前 mylist: 17 89 7 14 99 66 66 6 2 17 17
//移除后 mylist: 17 89 7 14 99 66 6 2 17

6.4 merge()

merge():合并已排序的列表,必须是升序的,否则程序会崩溃!!

cpp 复制代码
void test10()
{
    list<int> list1({ 1,2,3,4,5 });
	list<int> list2({ 88,99 });
	printList(list1, "排序前 mylist");
	list1.merge(list2);
	printList(list1, "排序后 mylist");
}

//排序前 mylist: 1 2 3 4 5
//排序后 mylist: 1 2 3 4 5 88 99

6.5 sort()

字符串排序先按照第一个字符进行比较ASCLL码值,相同再比较第二个字符!!

cpp 复制代码
void test10()
{
	list<string> sl = { "acb","efg","qwe","qqc","aad","aw" };
	for (auto& e : sl)
	{
		cout << e << " ";
	}
	cout << endl;
	sl.sort();
	for (auto& e : sl)
	{
		cout << e << " ";
	}
	cout << endl;
}

//排序前:acb efg qwe qqc aad aw
//排序后:aad acb aw efg qqc qwe

6.6 reverse()

reverse():逆置元素

cpp 复制代码
void test11()
{
	list<int> mylist({ 17,89,7,14,99,66,66,6,2,17,17 });
	printList(mylist, "反转前 mylist");
	mylist.reverse();
	printList(mylist, "反转后 mylist");
}

//反转前 mylist: 17 89 7 14 99 66 66 6 2 17 17
//反转后 mylist: 17 17 2 6 66 66 99 14 7 89 17

那么list的相关介绍就到这里,下期将对list的结构和常用的结构进行模拟实现,敬请期待~

相关推荐
小邓睡不饱耶2 小时前
使用Scala实现手机号码归属地查询系统
开发语言·windows·scala
diediedei2 小时前
高性能计算通信库
开发语言·c++·算法
雾岛听蓝2 小时前
C++11新特性(可变参数模板、新的类功能、STL中的一些新变化)
开发语言·c++·经验分享·笔记
lxl13072 小时前
学习C++(6)日期类的实现+取地址运算符重载
开发语言·c++·学习
fqbqrr2 小时前
2602c++,剪切板格式
c++
我材不敲代码2 小时前
Python爬虫介绍——简单了解一下爬虫
开发语言·爬虫·python
Howrun7772 小时前
可调用对象
开发语言·c++
2 小时前
java关于引用
java·开发语言
小小码农Come on2 小时前
QT布局介绍
开发语言·qt