1. list的介绍
1.1 list的介绍

关键特点:
-
list确实有一个哨兵节点(空节点):
-
不存储有效数据
-
用于简化边界条件处理
-
-
begin() 指向哨兵节点的下一个节点:
-
即第一个实际存储数据的节点
-
如果list为空,
begin() == end()
-
-
end() 指向哨兵节点:
-
哨兵节点不存储数据
-
不能解引用
end()(因为它是尾后位置)
-
-
循环链表 :哨兵节点的
prev指向最后一个节点,next指向第一个节点 -
简化操作:插入、删除等操作不需要特殊处理头尾情况
-
迭代器稳定:在list中插入/删除不会使其他迭代器失效(除了被删除元素的迭代器)
1.2 list的使用
list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已 达到可扩展的能力。以下为list中一些常见的重要接口。
1.2.1 list的构造
|-----------------------------------------------------------|-----------------------------|
| 构造函数( (constructor)) | 接口说明 |
| list (size_type n, const value_type& val = value_type()) | 构造的list中包含n个值为val的 元素 |
| list() | 构造空的list |
| list (const list& x) | 拷贝构造函数 |
| list (InputIterator first, InputIterator last) | 用[first, last)区间中的元素构造 list |
示例代码:
1. list(size_type n, const value_type& val = value_type())
cpp
// 创建n个相同的val
std::list<int> a(4, 5); // 4个5: {5,5,5,5}
std::list<char> b(3, 'A'); // 3个'A': {'A','A','A'}
2. list()
cpp
// 创建空列表
std::list<int> emptyList; // {}
3. list(const list& x)
cpp
// 复制另一个list
std::list<int> original = {1,2,3};
std::list<int> copy(original); // {1,2,3}
4. list(first, last)
cpp
// 从其他容器复制数据
std::vector<int> vec = {5,6,7,8};
std::list<int> lst(vec.begin(), vec.end()-1); // {5,6,7}
1.2.2 list iterator的使用
大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。
不懂迭代器的同学可以看一下[C++语法]-string类(用法详解及实现)-CSDN博客的2.2疑难解答部分。
|---------------|--------------------------------------------------------------------------|
| 函数声明 | 接口说明 |
| begin + end | 返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 |
| rbegin + rend | 返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位 置的reverse_iterator,即begin位置 |

【注意】
1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
1.2.3 list capacity
|-------|-------------------------------|
| 函数声明 | 接口说明 |
| empty | 检测list是否为空,是空返回true,否则返回false |
| size | 返回list中有效节点的个数 |
简单示例:
cpp
#include <iostream>
#include <list>
int main() {
// 1. empty() - 检查list是否为空
std::list<int> lst1; // 空list
std::list<int> lst2 = {1, 2}; // 非空list
std::cout << "lst1.empty(): " << lst1.empty() << std::endl; // true (1)
std::cout << "lst2.empty(): " << lst2.empty() << std::endl; // false (0)
// 2. size() - 获取元素个数
std::list<int> lst3 = {10, 20, 30, 40, 50};
std::cout << "lst3.size(): " << lst3.size() << std::endl; // 5
return 0;
}
实际应用:
cpp
// 清空list
std::list<int> nums = {1, 2, 3, 4, 5};
while (!nums.empty()) {
std::cout << "当前大小: " << nums.size() << std::endl;
nums.pop_front(); // 逐个删除元素
}
std::cout << "清空后大小: " << nums.size() << std::endl; // 0
1.2.4 list element access
cpp
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {10, 20, 30, 40, 50};
// 1. front() - 获取第一个元素
std::cout << "第一个元素: " << lst.front() << std::endl; // 10
// 2. back() - 获取最后一个元素
std::cout << "最后一个元素: " << lst.back() << std::endl; // 50
// 3. 可以修改元素
lst.front() = 100; // 修改第一个元素
lst.back() = 500; // 修改最后一个元素
std::cout << "\n修改后: ";
for (int n : lst) {
std::cout << n << " "; // 100 20 30 40 500
}
return 0;
}
1.2.5 list modifiers
|------------|------------------------------------------------|
| 函数声明 | 接口说明 |
| push_front | 在list首元素前插入值为val的元素(val 的类型就是 list 里存储的元素类型) |
| pop_front | 删除list中第一个元素 |
| push_back | 在list尾部插入值为val的元素 |
| pop_back | 删除list中最后一个元素 |
| insert | 在list position 位置中插入值为val的元素 |
| erase | 删除list position位置的元素 |
| swap | 交换两个list中的元素 |
| clear | 清空list中的有效元素 |
1. push_front(val) - 头部插入
cpp
std::list<int> lst = {2, 3};
lst.push_front(1); // 开头插入1 → {1, 2, 3}
2. pop_front() - 头部删除
cpp
std::list<int> lst = {1, 2, 3};
lst.pop_front(); // 删除1 → {2, 3}
3. push_back(val) - 尾部插入
cpp
std::list<int> lst = {1, 2};
lst.push_back(3); // 末尾插入3 → {1, 2, 3}
4. pop_back() - 尾部删除
cpp
std::list<int> lst = {1, 2, 3};
lst.pop_back(); // 删除3 → {1, 2}
5. insert(pos, val) - 指定位置插入
cpp
std::list<int> lst = {1, 3};
auto it = lst.begin();
++it; // 指向3
lst.insert(it, 2); // 在第二个位置插入2 → {1, 2, 3}
6. erase(pos) - 指定位置删除
cpp
std::list<int> lst = {1, 2, 3};
auto it = lst.begin();
++it; // 指向2
lst.erase(it); // 删除2 → {1, 3}
7. swap(other) - 交换两个list
cpp
std::list<int> a = {1, 2};
std::list<int> b = {3, 4};
a.swap(b); // a = {3, 4}, b = {1, 2}
8. clear() - 清空list
cpp
std::list<int> lst = {1, 2, 3};
lst.clear(); // lst = {}
1.2.6 list的迭代器失效
前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
cpp
void TestListIterator1()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array+sizeof(array)/sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
其赋值
l.erase(it);
++it;
}
}
// 改正
void TestListIterator()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array+sizeof(array)/sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
l.erase(it++); // it = l.erase(it);
}
}
学会了就给博主点个赞呗?(✪ω✪)
---------(如有问题,欢迎评论区提问)---------