为什么要学习list?什么是list?

listC++ 标准模板库中的一个容器,它实现了双向链表的数据结构。双向链表由一系列节点组成,每个节点包含一个数据元素两个指针,分别指向前一个节点后一个节点。在链表的任意位置进行插入和删除操作的时间复杂度都是O(1) 。这使得它在需要频繁插入和删除元素的场景下表现出色,比如实现一个任务调度器,需要不断地添加新任务、移除已完成的任务

list 也是一种很常用的容器,对于链表的处理提供了极大的便利性

在这里插入图片描述

list 的主要特征可总结为:

  1. list 是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代
  2. list 的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素
  3. listforward_list 非常相似:最主要的不同在于 forward_list 是单链表,只能朝前迭代,已让其更简单高效
  4. 与其他的序列式容器相比(arrayvectordeque),list 通常在任意位置进行插入、移除元素的执行效率更好。
  5. 与其他序列式容器相比,listforward_list 最大的缺陷是不支持任意位置的随机访问,比如:要访问 list 的第 6 个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list 还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大 list 来说这可能是一个重要的因素)

在这里插入图片描述

list类对象的常见构造

在这里插入图片描述

list作为一个类也有构造函数,析构函数,=运算符重载,我们重点介绍构造函数里的功能

函数名 功能说明
list() 无参构造
list (size_type n, const value_type& val = value_type()) 构造并初始化n个val
list (const list& x) 拷贝构造
list (InputIterator first, InputIterator last) 使用迭代器进行初始化构造

💻代码测试示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <list>
using namespace std;

int main()
{
list<int> first;
list<int> second(4, 100);
list<int> third(second.begin(), second.end());
list<int> fourth(third);

int myints[] = { 16,2,77,29 };
list<int> fifth(myints, myints + sizeof(myints) / sizeof(int));

cout << "The contents of fifth are: ";
for (list<int>::iterator it = fifth.begin(); it != fifth.end(); it++)
{
cout << *it << ' ';
}
cout << endl;

return 0;
}

⌨️代码输出示例:

在这里插入图片描述

list类对象的容量操作

在这里插入图片描述

因为是链表,所以对容量的操作并不需要太多,大部分是通过创建节点并链接实现

函数名 功能说明
empty 检测list是否为空,是返回true,否则返回false
size 返回list中有效节点的个数
max_size 返回链表能存储的最多节点个数

💻代码测试示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <list>
using namespace std;

int main()
{
list<int> lt;
cout << "empty:" << lt.empty() << endl;
cout << "size:" << lt.size() << endl;
cout << "max_size:" << lt.max_size() << endl;
return 0;
}

⌨️代码输出示例:

在这里插入图片描述

list类对象的迭代器

在这里插入图片描述

list 的迭代器和 vector 的基本使用方法一致,但是底层的迭代器结构不同,在 list 底层结构剖析有详细的解答

传送门:

函数名 功能说明
begin + end 迭代器:begin 获取开头一个节点 + end 获取最后一个节点下一个位置
rbegin + rend 反向迭代器:rbegin 获取最后一个节点 + end 获取开头一个节点上一个位置
cbegin + cend begin + end 一样,但是常量迭代器只读
crbegin + crend rbegin + rend 一样,但是反向常量迭代器只读

🔥值得注意的是:

  1. beginend 为正向迭代器,对迭代器执行 ++ 操作,迭代器向后移动
  2. rbegin(end)rend(begin) 为反向迭代器,对迭代器执行 ++ 操作,迭代器向前移动

在这里插入图片描述

💻代码测试示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <list>
using namespace std;

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

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

cout << "反向迭代器:";
list<int>::reverse_iterator it1 = lt.rbegin();
while (it1 != lt.rend())
{
cout << *it1 << " ";
++it1;
}
cout << endl;
}

⌨️代码输出示例:

在这里插入图片描述

list类对象的元素修改

在这里插入图片描述

emplace 的实现涉及 C++11 左值右值的知识,等到后面再拓展

函数名 功能说明
assign 将新的内容赋值给链表
push_front list 首元素前插入值为 val 的元素
pop_front 删除 list 中第一个元素
push_back list 尾部插入值为 val 的元素
pop_back 删除 list 中最后一个元素
insert list position 位置中插入值为 val 的元素
erase 删除 list position 位置的元素
swap 交换两个 list 中的元素
resize 将有效数据的个数增加或减少 n 个,多出的空间用默认值,少的截断即可
clear 清空 list 中的有效元素

💻代码测试示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <iostream>
#include <list>
using namespace std;

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

cout << "lt:";
list<int>::iterator it1 = lt.begin();
while (it1 != lt.end())
{
cout << *it1 << " ";
++it1;
}
cout << endl;

lt.assign(4, 0);
cout << "assign:";
list<int>::iterator it2 = lt.begin();
while (it2 != lt.end())
{
cout << *it2 << ' ';
it2++;
}
cout << endl;

lt.push_front(1);
cout << "push_front:";
list<int>::iterator it3 = lt.begin();
while (it3 != lt.end())
{
cout << *it3 << ' ';
it3++;
}
cout << endl;

lt.pop_front();
cout << "pop_front:";
list<int>::iterator it4 = lt.begin();
while (it4 != lt.end())
{
cout << *it4 << ' ';
it4++;
}
cout << endl;

lt.push_back(5);
cout << "push_back:";
list<int>::iterator it5 = lt.begin();
while (it5 != lt.end())
{
cout << *it5 << ' ';
it5++;
}
cout << endl;

lt.pop_back();
cout << "pop_back:";
list<int>::iterator it6 = lt.begin();
while (it6 != lt.end())
{
cout << *it6 << ' ';
it6++;
}
cout << endl;

list<int>::iterator it7 = lt.begin();
int num1 = 3;
while (--num1)
{
it7++;
}
list<int>::iterator pos = it7;
lt.insert(pos, 3, 1);
cout << "insert:";
list<int>::iterator it8 = lt.begin();
while (it8 != lt.end())
{
cout << *it8 << ' ';
it8++;
}
cout << endl;

list<int>::iterator it9 = lt.begin();
int num2 = 3;
while (--num2)
{
it9++;
}
list<int>::iterator pos1 = it9;
list<int>::iterator it10 = lt.begin();
int num3 = 6;
while (--num3)
{
it10++;
}
list<int>::iterator pos2 = it10;
lt.erase(pos1, pos2);
cout << "erase:";
list<int>::iterator it11 = lt.begin();
while (it11 != lt.end())
{
cout << *it11 << ' ';
it11++;
}
cout << endl;

list<int> ltt;
ltt.push_back(10);
ltt.push_back(20);
ltt.push_back(30);
ltt.push_back(40);
cout << "ltt:";
list<int>::iterator it12 = ltt.begin();
while (it12 != ltt.end())
{
cout << *it12 << ' ';
it12++;
}
cout << endl;

swap(lt, ltt);
cout << "swap:" << ' ' << "lt:";
list<int>::iterator it13 = lt.begin();
while (it13 != lt.end())
{
cout << *it13 << ' ';
it13++;
}
cout << ' ' << "ltt:";
list<int>::iterator it14 = ltt.begin();
while (it14 != ltt.end())
{
cout << *it14 << ' ';
it14++;
}
cout << endl;

lt.resize(10);
cout << "resize:" << lt.size() << endl;

lt.clear();
cout << "clear:";
list<int>::iterator it15 = lt.begin();
while (it15 != lt.end())
{
cout << *it15 << ' ';
it15++;
}
cout << endl;

return 0;
}

⌨️代码输出示例:

在这里插入图片描述

list类对象的链表操作

在这里插入图片描述

这一部分针对链表拓展了一些新的函数

函数名 功能说明
splice 将一个 list 中的元素转移到另一个 list
remove 移除 list 中所有等于指定值的元素
remove_if 移除 list 满足特定条件的所有元素
unique list 中移除连续重复的元素
merge 将两个已排序的列表合并成一个有序列表
sort list 中的元素进行排序
reverse list 中的元素顺序进行反转

🔥值得注意的是: remove_ifuniquemerge 涉及谓词等知识,放到后面讲

💻代码测试示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <list>
using namespace std;

int main()
{
list<int> lt;
lt.push_back(3);
lt.push_back(2);
lt.push_back(1);
lt.push_back(4);
cout << "lt:";
list<int>::iterator it1 = lt.begin();
while (it1 != lt.end())
{
cout << *it1 << ' ';
it1++;
}
cout << endl;

list<int> ltt;
ltt.push_back(10);
ltt.push_back(20);
ltt.push_back(30);
ltt.push_back(40);
cout << "ltt:";
list<int>::iterator it2 = ltt.begin();
while (it2 != ltt.end())
{
cout << *it2 << ' ';
it2++;
}
cout << endl;

lt.splice(lt.begin(), ltt);
cout << "splice:";
list<int>::iterator it3 = lt.begin();
while (it3 != lt.end())
{
cout << *it3 << ' ';
it3++;
}
cout << endl;

lt.remove(40);
cout << "remove:";
list<int>::iterator it4 = lt.begin();
while (it4 != lt.end())
{
cout << *it4 << ' ';
it4++;
}
cout << endl;

lt.sort();
cout << "sort:";
list<int>::iterator it5 = lt.begin();
while (it5 != lt.end())
{
cout << *it5 << ' ';
it5++;
}
cout << endl;

lt.reverse();
cout << "reverse:";
list<int>::iterator it6 = lt.begin();
while (it6 != lt.end())
{
cout << *it6 << ' ';
it6++;
}
cout << endl;
return 0;
}

s
⌨️代码输出示例:

在这里插入图片描述


希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

请添加图片描述