-
list 是一种序列式容器,支持在常数时间内在任意位置进行插入和删除操作,并可以双向迭代(即向前或向后遍历)。
-
list 的底层采用双向链表结构。链表中每个元素都存储在一个独立的节点中,节点之间通过指针相连,分别指向其前驱节点和后继节点。
-
list 与 forward_list 十分相似,主要区别在于 forward_list 是单向链表,仅支持向前迭代,因此结构更简单,在某些场景下效率更高。
-
相较于其他序列式容器(如 array、vector、deque),list 在任意位置执行插入和删除操作通常具有更好的性能表现。
-
然而,与其他序列式容器相比,list 和 forward_list 最大的不足是不支持随机访问。例如,若要访问 list 中的第 6 个元素,必须从某个已知位置(如头部或尾部)开始逐个迭代到达目标位置,所需时间为线性级。此外,list 每个节点都需要额外空间存储前后节点的指针信息,对于存储元素较小但链表规模较大的情况,这部分开销可能成为一个重要考虑因素。
一.list的构造函数

也就是4种构造函数
-
默认构造:创建空列表
-
填充构造:创建包含n个相同元素的列表
-
范围构造:从已有的迭代器范围创建列表(可以是数组、vector、list等)
-
拷贝构造:创建另一个列表的完整副本(深拷贝)
cpp
#include <iostream>
#include <list>
int main() {
// 1. 默认构造
std::list<int> list1;
std::cout << "Default constructor - size: " << list1.size() << std::endl;
// 2. 填充构造
std::list<int> list2(4, 88); // 4个元素,都是88
std::cout << "Fill constructor - size: " << list2.size() << std::endl;
// 3. 范围构造
int values[] = {1, 2, 3, 4, 5};
std::list<int> list3(values, values + 3); // 取前3个元素
std::cout << "Range constructor - size: " << list3.size() << std::endl;
// 4. 拷贝构造
std::list<int> list4(list2);
std::cout << "Copy constructor - size: " << list4.size() << std::endl;
return 0;
}
二.list的容量操作
- empty
- 作用:判断容器是否为空。
- 返回值:布尔值(true 表示容器为空,false 表示不为空)。
- size
- 作用:返回容器中当前元素的个数。
- 返回值:一个无符号整数(通常是 size_t 类型)。
cpp
#include <iostream>
#include <list>
int main() {
// 创建list的四种方法
std::cout << "=== 创建list的四种方法 ===" << std::endl;
// 1. 空list
std::list<int> list1;
std::cout << "1. 空list: size=" << list1.size()
<< ", empty=" << (list1.empty() ? "true" : "false") << std::endl;
// 2. 包含5个100的list
std::list<int> list2(5, 100);
std::cout << "2. 5个100: size=" << list2.size()
<< ", empty=" << (list2.empty() ? "true" : "false") << std::endl;
// 3. 从数组创建list
int arr[] = {1, 2, 3};
std::list<int> list3(arr, arr + 3);
std::cout << "3. 从数组创建: size=" << list3.size()
<< ", empty=" << (list3.empty() ? "true" : "false") << std::endl;
// 4. 拷贝list
std::list<int> list4(list2);
std::cout << "4. 拷贝list: size=" << list4.size()
<< ", empty=" << (list4.empty() ? "true" : "false") << std::endl;
std::cout << "\n=== empty()方法示例 ===" << std::endl;
// 检查list是否为空
std::list<int> mylist;
if (mylist.empty()) {
std::cout << "mylist是空的" << std::endl;
}
// 添加一个元素
mylist.push_back(10);
if (!mylist.empty()) {
std::cout << "mylist现在不是空的" << std::endl;
}
std::cout << "\n=== size()方法示例 ===" << std::endl;
// 查看list大小
std::list<int> numbers = {1, 2, 3, 4, 5};
std::cout << "numbers有" << numbers.size() << "个元素" << std::endl;
// 添加元素
numbers.push_back(6);
std::cout << "添加一个元素后,numbers有" << numbers.size() << "个元素" << std::endl;
// 删除元素
numbers.pop_front();
std::cout << "删除一个元素后,numbers有" << numbers.size() << "个元素" << std::endl;
std::cout << "\n=== 综合示例 ===" << std::endl;
// 清空list
while (!numbers.empty()) {
std::cout << "当前有" << numbers.size() << "个元素,移除一个" << std::endl;
numbers.pop_front();
}
std::cout << "现在numbers是空的吗?" << (numbers.empty() ? "是" : "否") << std::endl;
std::cout << "当前大小: " << numbers.size() << std::endl;
return 0;
}

三.list的成员访问操作
由于 list 是链表结构,不支持像数组或 vector 那样通过下标 ([]) 或 at() 进行随机访问,它仅提供了两个最直接的方法来获取其两端的元素。
- front
- 作用:返回对 list 中第一个元素的引用。
- 要求:容器不能为空。在调用此函数前,应使用 empty() 进行检查,否则如果对空 list 调用 front() 会导致未定义行为。
- 使用场景:常用于获取、修改或检查链表的头部元素。
- back
- 作用:返回对 list 中最后一个元素的引用。
- 要求:容器不能为空。在调用此函数前,应使用 empty() 进行检查,否则如果对空 list 调用 back() 会导致未定义行为。
- 使用场景:常用于获取、修改或检查链表的尾部元素。
总结与重要提醒:
- 双向访问:front 和 back 体现了 list 作为双向链表的特性,可以高效地从两端操作数据。
- 非随机访问:list 没有提供 operator[] 或 at() 成员函数,因为链表无法在常数时间内跳到任意位置。
- 安全第一:使用这两个函数前,务必确保容器非空,这是防止程序崩溃的关键。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== front()和back()方法示例 ===" << std::endl;
// 创建一个list
std::list<int> numbers = {10, 20, 30, 40, 50};
// 获取第一个和最后一个元素
std::cout << "第一个元素: " << numbers.front() << std::endl;
std::cout << "最后一个元素: " << numbers.back() << std::endl;
// 修改第一个和最后一个元素
numbers.front() = 100;
numbers.back() = 500;
std::cout << "修改后:" << std::endl;
std::cout << "第一个元素: " << numbers.front() << std::endl;
std::cout << "最后一个元素: " << numbers.back() << std::endl;
std::cout << "\n=== 安全访问示例 ===" << std::endl;
// 创建一个空的list
std::list<int> emptyList;
// 安全访问:先检查是否为空
if (!emptyList.empty()) {
std::cout << "第一个元素: " << emptyList.front() << std::endl;
std::cout << "最后一个元素: " << emptyList.back() << std::endl;
} else {
std::cout << "list是空的,不能使用front()和back()" << std::endl;
}
std::cout << "\n=== 实际应用示例 ===" << std::endl;
// 创建队列(使用list)
std::list<int> queue;
// 入队
queue.push_back(1);
queue.push_back(2);
queue.push_back(3);
// 出队:获取并移除第一个元素
while (!queue.empty()) {
std::cout << "处理任务: " << queue.front() << std::endl;
queue.pop_front();
}
std::cout << "\n=== 创建栈(使用list)===" << std::endl;
// 创建栈
std::list<int> stack;
// 压栈
stack.push_back(100);
stack.push_back(200);
stack.push_back(300);
// 弹栈:获取并移除最后一个元素
while (!stack.empty()) {
std::cout << "弹出元素: " << stack.back() << std::endl;
stack.pop_back();
}
return 0;
}

四.list的成员修改操作
- assign
- 作用:用新的内容替换整个容器的所有元素。可以指定新元素的数量和值,或者用另一个区间的元素来赋值。
- 特点:调用后,容器原有的所有元素都会被替换/销毁。
cpp
#include <iostream>
#include <list>
#include<vector>
int main() {
std::cout << "=== assign方法示例 ===" << std::endl;
// 创建一个初始list
std::list<int> numbers = {1, 2, 3, 4, 5};
std::cout << "初始list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 1. 用n个相同值替换所有元素
std::cout << "\n1. 用5个100替换所有元素:" << std::endl;
numbers.assign(5, 100);
std::cout << "替换后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 2. 用另一个区间的元素替换
std::cout << "\n2. 用数组元素替换:" << std::endl;
int arr[] = {10, 20, 30};
numbers.assign(arr, arr + 3);
std::cout << "替换后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 3. 用另一个list的元素替换
std::cout << "\n3. 用另一个list的元素替换:" << std::endl;
std::list<int> otherList = {100, 200, 300, 400};
numbers.assign(otherList.begin(), otherList.end());
std::cout << "替换后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 4. 用vector的元素替换
std::cout << "\n4. 用vector的元素替换:" << std::endl;
std::vector<int> vec = {7, 8, 9, 10, 11, 12};
numbers.assign(vec.begin(), vec.end());
std::cout << "替换后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 5. 清空list
std::cout << "\n5. 清空list:" << std::endl;
numbers.assign(0, 0); // 分配0个元素
std::cout << "清空后大小: " << numbers.size()
<< ", 是否为空: " << (numbers.empty() ? "是" : "否") << std::endl;
return 0;
}

- emplace_front
- 作用:在链表头部直接构造并插入一个新元素。参数将直接传递给元素的构造函数。
- 优点:比 push_front 更高效,因为它避免了临时对象的创建和拷贝/移动操作(C++11引入)。
- push_front
- 作用:在链表头部插入一个已存在元素的副本。
- 对比: emplace_front 是"构造然后插入",push_front 是"拷贝/移动然后插入"。
- pop_front
- 作用:移除链表头部的第一个元素。
- 注意:容器不能为空。此函数不返回被移除的元素,如需获取该元素,应在调用前使用 front()。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== emplace_front、push_front、pop_front示例 ===" << std::endl;
std::list<int> numbers;
// 1. push_front - 在头部插入元素
std::cout << "\n1. 使用push_front添加元素:" << std::endl;
numbers.push_front(3);
numbers.push_front(2);
numbers.push_front(1);
std::cout << "当前list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 2. emplace_front - 在头部直接构造元素
std::cout << "\n2. 使用emplace_front添加元素:" << std::endl;
numbers.emplace_front(0);
numbers.emplace_front(-1);
std::cout << "当前list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 3. pop_front - 移除头部元素
std::cout << "\n3. 使用pop_front移除元素:" << std::endl;
// 先获取头部元素
std::cout << "移除前,头部元素: " << numbers.front() << std::endl;
// 移除头部元素
numbers.pop_front();
std::cout << "移除后,新头部元素: " << numbers.front() << std::endl;
std::cout << "当前list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 4. 连续移除所有元素
std::cout << "\n4. 连续pop_front移除所有元素:" << std::endl;
while (!numbers.empty()) {
std::cout << "准备移除: " << numbers.front() << std::endl;
numbers.pop_front();
}
std::cout << "最终list大小: " << numbers.size() << std::endl;
// 5. 安全使用pop_front
std::cout << "\n5. 安全使用pop_front:" << std::endl;
if (!numbers.empty()) {
numbers.pop_front(); // 不会执行,因为list为空
} else {
std::cout << "list为空,不能pop_front" << std::endl;
}
// 6. emplace_front与push_front对比
std::cout << "\n6. emplace_front与push_front对比:" << std::endl;
// 使用emplace_front直接构造
numbers.emplace_front(100);
std::cout << "添加后: " << numbers.front() << std::endl;
// 使用push_front插入已存在的值
int value = 200;
numbers.push_front(value);
std::cout << "添加后: " << numbers.front() << std::endl;
return 0;
}

- emplace_back
- 作用:在链表尾部直接构造并插入一个新元素。参数将直接传递给元素的构造函数。
- 优点:比 push_back 更高效(C++11引入)。
- push_back
- 作用:在链表尾部插入一个已存在元素的副本。最常用的添加元素的方法之一。
- pop_back
- 作用:移除链表尾部的最后一个元素。
- 注意:容器不能为空。此函数不返回被移除的元素,如需获取该元素,应在调用前使用 back()。
我们直接看例子
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== emplace_back、push_back、pop_back示例 ===" << std::endl;
std::list<int> numbers;
// 1. push_back - 在尾部插入元素
std::cout << "\n1. 使用push_back添加元素:" << std::endl;
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);
std::cout << "当前list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 2. emplace_back - 在尾部直接构造元素
std::cout << "\n2. 使用emplace_back添加元素:" << std::endl;
numbers.emplace_back(4);
numbers.emplace_back(5);
std::cout << "当前list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 3. pop_back - 移除尾部元素
std::cout << "\n3. 使用pop_back移除元素:" << std::endl;
// 先获取尾部元素
std::cout << "移除前,尾部元素: " << numbers.back() << std::endl;
// 移除尾部元素
numbers.pop_back();
std::cout << "移除后,新尾部元素: " << numbers.back() << std::endl;
std::cout << "当前list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 4. 连续移除所有元素
std::cout << "\n4. 连续pop_back移除所有元素:" << std::endl;
while (!numbers.empty()) {
std::cout << "准备移除: " << numbers.back() << std::endl;
numbers.pop_back();
}
std::cout << "最终list大小: " << numbers.size() << std::endl;
// 5. 安全使用pop_back
std::cout << "\n5. 安全使用pop_back:" << std::endl;
if (!numbers.empty()) {
numbers.pop_back(); // 不会执行,因为list为空
} else {
std::cout << "list为空,不能pop_back" << std::endl;
}
// 6. emplace_back与push_back对比
std::cout << "\n6. emplace_back与push_back对比:" << std::endl;
// 使用emplace_back直接构造
numbers.emplace_back(100);
std::cout << "添加后: " << numbers.back() << std::endl;
// 使用push_back插入已存在的值
int value = 200;
numbers.push_back(value);
std::cout << "添加后: " << numbers.back() << std::endl;
std::cout << "\n7. 综合示例 - 模拟栈操作:" << std::endl;
std::list<std::string> stack;
// 使用push_back模拟入栈
stack.push_back("任务1");
stack.push_back("任务2");
stack.push_back("任务3");
std::cout << "栈顶(最后添加的): " << stack.back() << std::endl;
// 使用pop_back模拟出栈
while (!stack.empty()) {
std::cout << "执行: " << stack.back() << std::endl;
stack.pop_back();
}
return 0;
}

- emplace
- 作用:在指定的迭代器位置之前直接构造并插入一个新元素。这是 insert 的高效版本。
- 优点:适用于在链表中间任意位置插入,且无需创建临时对象。
- insert
- 作用:在指定的迭代器位置之前插入一个或多个已存在元素的副本。可以插入单个元素、多个相同元素或另一个容器的一段元素。
- 核心优势:对于 list,在任意位置的插入操作都是常数时间 O(1),这是其相对于 vector 和 deque 的巨大优势。
我们直接看一个例子
cpp
#include <iostream>
#include <list>
#include <vector>
int main() {
std::cout << "=== insert和emplace方法示例 ===" << std::endl;
std::list<int> numbers = {1, 2, 3, 4, 5};
std::cout << "初始list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 1. insert - 在指定位置插入单个元素
std::cout << "\n1. insert插入单个元素:" << std::endl;
auto it = numbers.begin();
++it; // 指向第二个元素
numbers.insert(it, 100); // 在第二个位置前插入100
std::cout << "在第二个位置前插入100后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 2. insert - 插入多个相同元素
std::cout << "\n2. insert插入多个相同元素:" << std::endl;
it = numbers.end();
numbers.insert(it, 3, 999); // 在末尾插入3个999
std::cout << "在末尾插入3个999后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 3. insert - 插入另一个容器的元素
std::cout << "\n3. insert插入数组元素:" << std::endl;
int arr[] = {7, 8, 9};
it = numbers.begin();
std::advance(it, 3); // 移动到第4个位置
numbers.insert(it, arr, arr + 3);
std::cout << "在第4个位置插入数组后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 4. emplace - 在指定位置直接构造元素
std::cout << "\n4. emplace直接构造元素:" << std::endl;
std::list<std::string> words = {"apple", "banana", "cherry"};
std::cout << "初始字符串list: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << std::endl;
auto word_it = words.begin();
++word_it; // 指向第二个元素
// 使用emplace直接构造字符串
words.emplace(word_it, "orange");
std::cout << "在第二个位置插入orange后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << std::endl;
// 5. insert返回值 - 返回指向新插入元素的迭代器
std::cout << "\n5. insert返回值示例:" << std::endl;
std::list<int> list2 = {10, 20, 30};
it = list2.begin();
++it;
auto new_it = list2.insert(it, 15); // 插入15
std::cout << "插入的元素: " << *new_it << std::endl;
// 在刚插入的元素后继续插入
list2.insert(++new_it, 16);
std::cout << "多次插入后: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
// 6. 性能对比:insert vs emplace
std::cout << "\n6. insert和emplace对比:" << std::endl;
std::list<std::string> list3;
// 使用insert需要创建临时对象
std::string temp = "hello";
list3.insert(list3.begin(), temp);
std::cout << "使用insert: " << list3.front() << std::endl;
// 使用emplace直接构造,没有临时对象
list3.emplace(list3.begin(), "world");
std::cout << "使用emplace: " << list3.front() << std::endl;
return 0;
}

- erase
- 作用:移除一个指定位置的元素,或移除一个迭代器区间 [first, last) 内的所有元素。
- 返回值:返回指向被移除元素之后那个元素的迭代器。这是一个非常重要的特性,用于在遍历中安全地删除元素。
- 核心优势:对于 list,在任意位置的删除操作都是常数时间 O(1)。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== erase方法示例 ===" << std::endl;
// 1. 删除指定位置的单个元素
std::cout << "\n1. 删除指定位置的单个元素:" << std::endl;
std::list<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9};
std::cout << "初始list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
auto it = numbers.begin();
std::advance(it, 3); // 指向第4个元素(下标从0开始)
// 删除第4个元素
numbers.erase(it);
std::cout << "删除第4个元素后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 2. 删除一个区间内的元素
std::cout << "\n2. 删除一个区间内的元素:" << std::endl;
std::list<int> list2 = {10, 20, 30, 40, 50, 60, 70};
std::cout << "初始list: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
auto first = list2.begin();
std::advance(first, 2); // 指向第3个元素
auto last = first;
std::advance(last, 3); // 指向第6个元素
// 删除从第3个到第5个元素([first, last)区间)
list2.erase(first, last);
std::cout << "删除第3到第5个元素后: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
// 3. 使用erase返回值
std::cout << "\n3. 使用erase返回值:" << std::endl;
std::list<int> list3 = {1, 2, 3, 4, 5};
std::cout << "初始list: ";
for (int n : list3) std::cout << n << " ";
std::cout << std::endl;
it = list3.begin();
while (it != list3.end()) {
if (*it == 3) {
it = list3.erase(it); // 删除3,返回下一个元素的迭代器
} else {
++it;
}
}
std::cout << "删除所有3后: ";
for (int n : list3) std::cout << n << " ";
std::cout << std::endl;
// 4. 在循环中删除特定条件元素
std::cout << "\n4. 在循环中删除特定条件元素:" << std::endl;
std::list<int> list4 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
std::cout << "初始list: ";
for (int n : list4) std::cout << n << " ";
std::cout << std::endl;
it = list4.begin();
while (it != list4.end()) {
if (*it % 2 == 0) { // 删除偶数
it = list4.erase(it);
} else {
++it;
}
}
std::cout << "删除所有偶数后: ";
for (int n : list4) std::cout << n << " ";
std::cout << std::endl;
// 5. 删除所有元素
std::cout << "\n5. 删除所有元素:" << std::endl;
std::list<int> list5 = {1, 2, 3, 4, 5};
std::cout << "初始大小: " << list5.size() << std::endl;
// 删除从开始到结束的所有元素
list5.erase(list5.begin(), list5.end());
std::cout << "删除所有元素后大小: " << list5.size() << std::endl;
return 0;
}

- swap
- 作用:交换两个 list 容器的全部内容。此操作非常快,因为它只交换两个容器内部的指针(如头指针、尾指针等),而不交换每个元素。
- 优点:常数时间复杂度 O(1),且不会使指向容器内元素的迭代器、引用和指针失效(它们会指向交换后的新容器中的同一元素)。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== swap方法示例 ===" << std::endl;
// 创建两个不同的list
std::list<int> list1 = {1, 2, 3};
std::list<int> list2 = {10, 20, 30, 40};
std::cout << "交换前:" << std::endl;
std::cout << "list1: ";
for (int n : list1) std::cout << n << " ";
std::cout << "\nlist2: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
// 1. 交换两个list
list1.swap(list2);
std::cout << "\n交换后:" << std::endl;
std::cout << "list1: ";
for (int n : list1) std::cout << n << " ";
std::cout << "\nlist2: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
// 2. 验证swap是O(1)操作
std::cout << "\n2. 验证swap是常数时间操作:" << std::endl;
std::cout << "交换前大小 - list1:" << list1.size()
<< " list2:" << list2.size() << std::endl;
// 再次交换
list1.swap(list2);
std::cout << "再次交换后大小 - list1:" << list1.size()
<< " list2:" << list2.size() << std::endl;
// 3. swap不会使迭代器失效
std::cout << "\n3. swap不会使迭代器失效:" << std::endl;
// 获取list1中第二个元素的迭代器
auto it1 = list1.begin();
++it1; // 指向第二个元素(2)
// 获取list2中第三个元素的迭代器
auto it2 = list2.begin();
std::advance(it2, 2); // 指向第三个元素(30)
std::cout << "交换前:" << std::endl;
std::cout << "it1指向: " << *it1 << " (list1的第2个元素)" << std::endl;
std::cout << "it2指向: " << *it2 << " (list2的第3个元素)" << std::endl;
// 交换list1和list2
list1.swap(list2);
std::cout << "\n交换后:" << std::endl;
std::cout << "it1仍然指向: " << *it1 << " (但现在在list2中)" << std::endl;
std::cout << "it2仍然指向: " << *it2 << " (但现在在list1中)" << std::endl;
// 4. 使用std::swap也可以交换list
std::cout << "\n4. 使用std::swap交换list:" << std::endl;
std::list<int> a = {100, 200};
std::list<int> b = {300, 400, 500};
std::cout << "交换前: a = ";
for (int n : a) std::cout << n << " ";
std::cout << ", b = ";
for (int n : b) std::cout << n << " ";
std::cout << std::endl;
std::swap(a, b); // 标准库的swap
std::cout << "交换后: a = ";
for (int n : a) std::cout << n << " ";
std::cout << ", b = ";
for (int n : b) std::cout << n << " ";
std::cout << std::endl;
// 5. 性能比较:swap vs 赋值
std::cout << "\n5. swap与赋值的性能比较:" << std::endl;
std::list<int> x(1000, 1); // 1000个1
std::list<int> y(1000, 2); // 1000个2
std::cout << "交换前: x大小=" << x.size()
<< ", y大小=" << y.size() << std::endl;
// swap是O(1),只交换指针
x.swap(y);
std::cout << "swap后: x大小=" << x.size()
<< ", y大小=" << y.size() << std::endl;
// 赋值是O(n),需要复制所有元素
x = y; // 将y的所有元素复制到x
std::cout << "赋值后: x大小=" << x.size()
<< ", y大小=" << y.size() << std::endl;
return 0;
}


- resize
- 作用:改变容器的大小。
- 如果新尺寸 (n) 小于当前尺寸,则容器尾部多余的元素会被销毁。
- 如果新尺寸大于当前尺寸,则会在容器尾部添加额外数量的元素(可以指定初始化值,默认为值初始化的新元素)。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== resize方法示例 ===" << std::endl;
// 1. 创建初始list
std::list<int> numbers = {1, 2, 3, 4, 5};
std::cout << "初始list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 2. 缩小list大小
std::cout << "\n2. 缩小list大小(resize到3):" << std::endl;
numbers.resize(3); // 只保留前3个元素
std::cout << "缩小后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 3. 扩大list大小(使用默认值0)
std::cout << "\n3. 扩大list大小(resize到6,默认值0):" << std::endl;
numbers.resize(6); // 扩大,新元素为0
std::cout << "扩大后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 4. 扩大list大小(指定新元素的值)
std::cout << "\n4. 扩大list大小(resize到8,指定值99):" << std::endl;
numbers.resize(8, 99); // 扩大,新元素为99
std::cout << "扩大后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 5. 缩小到空list
std::cout << "\n5. 缩小到空list(resize到0):" << std::endl;
numbers.resize(0);
std::cout << "缩小后大小: " << numbers.size() << std::endl;
std::cout << "list是否为空: " << (numbers.empty() ? "是" : "否") << std::endl;
// 6. 从空list扩大
std::cout << "\n6. 从空list扩大(resize到5,指定值7):" << std::endl;
numbers.resize(5, 7); // 创建5个元素,都是7
std::cout << "扩大后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 7. resize与构造函数对比
std::cout << "\n7. resize与构造函数对比:" << std::endl;
// 构造函数创建10个100
std::list<int> list1(10, 100);
std::cout << "构造函数list(10, 100): ";
for (int i = 0; i < 5; ++i) { // 只显示前5个
auto it = list1.begin();
std::advance(it, i);
std::cout << *it << " ";
}
std::cout << "... 大小: " << list1.size() << std::endl;
// 使用resize达到相同效果
std::list<int> list2;
list2.resize(10, 100);
std::cout << "resize(10, 100): ";
for (int i = 0; i < 5; ++i) {
auto it = list2.begin();
std::advance(it, i);
std::cout << *it << " ";
}
std::cout << "... 大小: " << list2.size() << std::endl;
// 8. 字符串list的resize示例
std::cout << "\n8. 字符串list的resize示例:" << std::endl;
std::list<std::string> words = {"apple", "banana", "cherry"};
std::cout << "初始字符串list: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
// 缩小
words.resize(2);
std::cout << "resize(2)后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
// 扩大,使用默认值""
words.resize(4);
std::cout << "resize(4)后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
// 扩大,指定新元素的值
words.resize(6, "fruit");
std::cout << "resize(6, \"fruit\")后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
return 0;
}

- clear
- 作用:移除容器内的所有元素,使 size() 变为 0。容器本身(内存占用)可能不会改变,但所有元素对象都会被销毁。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== clear方法示例 ===" << std::endl;
// 1. 创建并清空一个list
std::list<int> numbers = {1, 2, 3, 4, 5};
std::cout << "初始list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 使用clear清空list
numbers.clear();
std::cout << "clear()后大小: " << numbers.size() << std::endl;
std::cout << "list是否为空: " << (numbers.empty() ? "是" : "否") << std::endl;
// 2. 清空后可以重新添加元素
std::cout << "\n2. 清空后重新添加元素:" << std::endl;
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);
std::cout << "添加后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 3. 再次清空
numbers.clear();
std::cout << "再次clear()后大小: " << numbers.size() << std::endl;
// 4. clear与resize(0)对比
std::cout << "\n4. clear()与resize(0)对比:" << std::endl;
std::list<int> list1 = {1, 2, 3};
std::list<int> list2 = {1, 2, 3};
std::cout << "list1初始大小: " << list1.size() << std::endl;
std::cout << "list2初始大小: " << list2.size() << std::endl;
list1.clear();
list2.resize(0);
std::cout << "list1 clear()后大小: " << list1.size() << std::endl;
std::cout << "list2 resize(0)后大小: " << list2.size() << std::endl;
// 5. 字符串list的clear操作
std::cout << "\n5. 字符串list的clear操作:" << std::endl;
std::list<std::string> words = {"apple", "banana", "cherry", "date"};
std::cout << "初始字符串list: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
words.clear();
std::cout << "clear()后: 大小=" << words.size()
<< ", 是否为空: " << (words.empty() ? "是" : "否") << std::endl;
// 6. 多次clear是安全的
std::cout << "\n6. 多次clear是安全的:" << std::endl;
std::list<int> list3;
list3.clear(); // 已经是空的,但clear仍然安全
list3.clear(); // 再次clear也安全
list3.clear(); // 多次clear不会出错
std::cout << "多次clear后大小: " << list3.size() << std::endl;
// 7. clear与其他操作结合
std::cout << "\n7. clear与其他操作结合:" << std::endl;
std::list<int> data;
// 添加一些数据
for (int i = 0; i < 5; ++i) {
data.push_back(i * 10);
}
std::cout << "添加数据后大小: " << data.size() << std::endl;
// 模拟数据处理
if (!data.empty()) {
std::cout << "处理数据..." << std::endl;
data.clear(); // 处理完后清空
std::cout << "处理完成,清空数据" << std::endl;
}
std::cout << "最终大小: " << data.size() << std::endl;
return 0;
}

五.list特有的结点操作
5.1. splice(拼接)
作用:将一个 list 中的元素(或整个 list)移动到另一个 list 的指定位置。这是链表特有的高效操作,因为只修改指针,不涉及元素的拷贝或移动。
特点:
- 非常高效(常数时间或线性时间,取决于移动的范围)。
- 源 list 中的元素会被移除,合并到目标 list 中。
- 有多个重载版本:可以移动单个元素、一个区间内的所有元素,或者整个 list。
我们看看splice的3种重载形式
1. 移动整个 list
cpp
void splice(const_iterator position, list& other);
void splice(const_iterator position, list&& other); // C++11 移动语义
参数意义:
- position:目标 list 中的位置,新元素会插入到这个位置之前
- other:源 list,它的所有元素会被移动到目标 list 中
示例:
cpp
list1.splice(list1.begin(), list2);
// 把list2的所有元素移动到list1的开头
// 操作后:list2为空,list2的所有元素在list1中
2. 移动单个元素
cpp
void splice(const_iterator position, list& other, const_iterator i);
参数意义:
- position:目标 list 中的位置,元素会插入到这个位置之前
- other:源 list,元素从这里移出
- i:源 list 中的迭代器,指向要移动的单个元素
示例:
cpp
auto it = list2.begin(); // 指向list2的第一个元素
list1.splice(list1.end(), list2, it);
// 把list2的第一个元素移动到list1的末尾
// 只移动一个元素,list2大小减1,list1大小加1
3. 移动一个区间
cpp
void splice(const_iterator position, list& other,
const_iterator first, const_iterator last);
参数意义:
- position:目标 list 中的位置,区间元素会插入到这个位置之前
- other:源 list,区间元素从这里移出
- first:源 list 中的起始迭代器,指向区间的开始位置(包含)
- last:源 list 中的结束迭代器,指向区间的结束位置(不包含)
示例:
cpp
auto first = list2.begin(); // 指向开始
auto last = list2.begin();
advance(last, 3); // 向前移动3位
list1.splice(list1.begin(), list2, first, last);
// 把list2的前3个元素(位置0,1,2)移动到list1的开头
// list2大小减3,list1大小加3
那么,接下来我们看一个完整的例子:
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== splice(拼接)方法示例 ===" << std::endl;
// 创建两个list
std::list<int> list1 = {1, 2, 3, 4, 5};
std::list<int> list2 = {10, 20, 30, 40, 50};
std::cout << "初始状态:" << std::endl;
std::cout << "list1: ";
for (int n : list1) std::cout << n << " ";
std::cout << " 大小: " << list1.size() << std::endl;
std::cout << "list2: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
// 1. 移动list2中的一个元素到list1
std::cout << "\n1. 移动list2中的一个元素到list1开头:" << std::endl;
auto it2 = list2.begin();
++it2; // 指向list2的第二个元素(20)
list1.splice(list1.begin(), list2, it2); // 把元素20移动到list1开头 ------ 移动单个元素的形式
std::cout << "操作后:" << std::endl;
std::cout << "list1: ";
for (int n : list1) std::cout << n << " ";
std::cout << " 大小: " << list1.size() << std::endl;
std::cout << "list2: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
// 2. 移动list2中的一段元素到list1
std::cout << "\n2. 移动list2中的一段元素到list1末尾:" << std::endl;
auto first = list2.begin();
auto last = list2.begin();
std::advance(last, 3); // 指向第4个元素
list1.splice(list1.end(), list2, first, last); // 移动前3个元素 ------ 移动一个区间的形式
std::cout << "操作后:" << std::endl;
std::cout << "list1: ";
for (int n : list1) std::cout << n << " ";
std::cout << " 大小: " << list1.size() << std::endl;
std::cout << "list2: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
// 3. 移动整个list2到list1
std::cout << "\n3. 移动整个list2到list1开头:" << std::endl;
// 首先恢复list2的内容
list2 = {100, 200, 300};
std::cout << "恢复list2后:" << std::endl;
std::cout << "list2: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
list1.splice(list1.begin(), list2); // 移动整个list2到list1开头 ------ 移动整个链表
std::cout << "操作后:" << std::endl;
std::cout << "list1: ";
for (int n : list1) std::cout << n << " ";
std::cout << " 大小: " << list1.size() << std::endl;
std::cout << "list2: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
// 4. 同一个list内部移动元素
std::cout << "\n4. 同一个list内部移动元素:" << std::endl;
std::list<int> list3 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
std::cout << "初始list3: ";
for (int n : list3) std::cout << n << " ";
std::cout << std::endl;
// 把第5个元素(5)移动到开头
auto pos = list3.begin();
std::advance(pos, 4); // 指向第5个元素(5)
auto element = pos;
list3.splice(list3.begin(), list3, element);
std::cout << "把5移动到开头后: ";
for (int n : list3) std::cout << n << " ";
std::cout << std::endl;
// 5. 实际应用:合并两个有序链表的一部分
std::cout << "\n5. 实际应用:合并有序链表的一部分:" << std::endl;
std::list<int> sorted1 = {1, 3, 5, 7, 9};
std::list<int> sorted2 = {2, 4, 6, 8, 10};
std::cout << "有序链表1: ";
for (int n : sorted1) std::cout << n << " ";
std::cout << std::endl;
std::cout << "有序链表2: ";
for (int n : sorted2) std::cout << n << " ";
std::cout << std::endl;
// 把sorted2中小于5的元素移动到sorted1中
auto it = sorted2.begin();
while (it != sorted2.end() && *it < 5) {
auto next = std::next(it);
sorted1.splice(sorted1.end(), sorted2, it);
it = next;
}
std::cout << "移动后:" << std::endl;
std::cout << "sorted1: ";
for (int n : sorted1) std::cout << n << " ";
std::cout << std::endl;
std::cout << "sorted2: ";
for (int n : sorted2) std::cout << n << " ";
std::cout << std::endl;
return 0;
}

- splice只修改指针,不复制元素,非常高效
- 源list中的元素被移除,转移到目标list
- 操作后迭代器仍然有效
- 时间复杂度:O(1)(移动单个元素或整个list)或O(n)(移动一个区间)
5.2. remove(移除)
作用:移除容器中所有值等于指定值的元素。
注意:
- 会遍历整个 list,删除所有匹配的元素。
- 时间复杂度为 O(n)。
- 与 erase 不同,它按值删除,而不是按位置。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== remove方法示例 ===" << std::endl;
// 1. 移除特定值的所有元素
std::cout << "\n1. 移除所有值为3的元素:" << std::endl;
std::list<int> numbers = {1, 2, 3, 4, 3, 5, 3, 6};
std::cout << "初始list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
numbers.remove(3); // 移除所有值为3的元素
std::cout << "remove(3)后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 2. 移除不存在的值
std::cout << "\n2. 移除不存在的值(100):" << std::endl;
std::list<int> list2 = {1, 2, 3, 4, 5};
std::cout << "初始list: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
list2.remove(100); // 移除100,但list中没有这个值
std::cout << "remove(100)后: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
// 3. 移除所有值为0的元素
std::cout << "\n3. 移除所有值为0的元素:" << std::endl;
std::list<int> list3 = {0, 1, 0, 2, 0, 3, 0, 4, 0};
std::cout << "初始list: ";
for (int n : list3) std::cout << n << " ";
std::cout << " 大小: " << list3.size() << std::endl;
list3.remove(0);
std::cout << "remove(0)后: ";
for (int n : list3) std::cout << n << " ";
std::cout << " 大小: " << list3.size() << std::endl;
// 4. 字符串list的remove操作
std::cout << "\n4. 字符串list的remove操作:" << std::endl;
std::list<std::string> words = {"apple", "banana", "apple", "cherry", "apple", "date"};
std::cout << "初始字符串list: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
words.remove("apple"); // 移除所有"apple"
std::cout << "remove(\"apple\")后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
return 0;
}

5.3. remove_if(条件移除)
- 作用:移除容器中所有满足特定条件的元素。需要一个谓词函数(返回 bool 的可调用对象)作为参数。
- 示例:删除所有偶数:myList.remove_if([](int n){ return n % 2 == 0; });
- 注意:同样需要遍历整个 list,时间复杂度为 O(n)。
cpp
#include <iostream>
#include <list>
// 自定义判断函数
bool isEven(int n) {
return n % 2 == 0;
}
bool isOdd(int n) {
return n % 2 != 0;
}
bool isGreaterThan5(int n) {
return n > 5;
}
int main() {
std::cout << "=== remove_if方法示例 ===" << std::endl;
// 1. 使用普通函数作为谓词
std::cout << "\n1. 使用普通函数删除所有偶数:" << std::endl;
std::list<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << "初始list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
numbers.remove_if(isEven); // 删除所有偶数
std::cout << "删除偶数后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 2. 使用lambda表达式(C++11)
std::cout << "\n2. 使用lambda表达式删除大于5的数:" << std::endl;
std::list<int> list2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << "初始list: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
// 使用lambda表达式
list2.remove_if([](int n) { return n > 5; });
std::cout << "删除大于5的数后: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
// 3. 删除字符串列表中长度小于3的字符串
std::cout << "\n3. 删除长度小于3的字符串:" << std::endl;
std::list<std::string> words = {"a", "ab", "abc", "abcd", "b", "bc", "bcd"};
std::cout << "初始字符串list: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
words.remove_if([](const std::string& s) { return s.length() < 3; });
std::cout << "删除长度小于3的字符串后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
// 4. 使用函数对象(仿函数)
std::cout << "\n4. 使用函数对象删除特定范围的数:" << std::endl;
// 定义一个函数对象
class Between3And7 {
public:
bool operator()(int n) const {
return n >= 3 && n <= 7;
}
};
std::list<int> list3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << "初始list: ";
for (int n : list3) std::cout << n << " ";
std::cout << " 大小: " << list3.size() << std::endl;
list3.remove_if(Between3And7()); // 删除3到7之间的数
std::cout << "删除3到7之间的数后: ";
for (int n : list3) std::cout << n << " ";
std::cout << " 大小: " << list3.size() << std::endl;
// 5. 删除所有负数
std::cout << "\n5. 删除所有负数:" << std::endl;
std::list<int> list4 = {-5, -2, 0, 3, -1, 4, 2, -3, 1};
std::cout << "初始list: ";
for (int n : list4) std::cout << n << " ";
std::cout << " 大小: " << list4.size() << std::endl;
list4.remove_if([](int n) { return n < 0; });
std::cout << "删除负数后: ";
for (int n : list4) std::cout << n << " ";
std::cout << " 大小: " << list4.size() << std::endl;
// 6. 删除所有重复的字母(大小写敏感)
std::cout << "\n6. 删除所有小写字母:" << std::endl;
std::list<char> letters = {'A', 'b', 'C', 'd', 'E', 'f', 'G', 'h'};
std::cout << "初始字符list: ";
for (char c : letters) std::cout << c << " ";
std::cout << " 大小: " << letters.size() << std::endl;
letters.remove_if([](char c) { return std::islower(c); });
std::cout << "删除小写字母后: ";
for (char c : letters) std::cout << c << " ";
std::cout << " 大小: " << letters.size() << std::endl;
// 7. 更复杂的条件:删除能被3整除且大于10的数
std::cout << "\n7. 删除能被3整除且大于10的数:" << std::endl;
std::list<int> list5 = {3, 6, 9, 12, 15, 18, 21, 24, 27, 30};
std::cout << "初始list: ";
for (int n : list5) std::cout << n << " ";
std::cout << " 大小: " << list5.size() << std::endl;
list5.remove_if([](int n) { return n > 10 && n % 3 == 0; });
std::cout << "删除能被3整除且大于10的数后: ";
for (int n : list5) std::cout << n << " ";
std::cout << " 大小: " << list5.size() << std::endl;
// 8. remove_if与remove的对比
std::cout << "\n8. remove_if与remove的对比:" << std::endl;
std::cout << "remove(value): 删除所有等于value的元素" << std::endl;
std::cout << "remove_if(pred): 删除所有使pred返回true的元素" << std::endl;
std::cout << "remove_if更灵活,可以实现任意条件删除" << std::endl;
return 0;
}

5.4. unique(去重)
作用:移除容器中连续重复的元素,只保留每组相同元素中的第一个。
注意:
- 通常在使用 sort() 之后调用,因为 unique 只能删除相邻的重复元素。
- 有重载版本可以接受一个二元谓词来自定义"相等"的比较方式。
- 时间复杂度为 O(n)。
特别注意需要是连续重复!!
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== unique方法示例 ===" << std::endl;
// 1. 删除连续重复的元素
std::cout << "\n1. 删除连续重复的元素:" << std::endl;
std::list<int> numbers = {1, 1, 2, 3, 3, 3, 4, 5, 5, 6};
std::cout << "初始list: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
numbers.unique(); // 删除连续重复的元素
std::cout << "unique()后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << " 大小: " << numbers.size() << std::endl;
// 2. 不连续的重复元素不会被删除
std::cout << "\n2. 不连续的重复元素不会被删除:" << std::endl;
std::list<int> list2 = {1, 2, 1, 3, 2, 4, 1, 5};
std::cout << "初始list: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
list2.unique();
std::cout << "unique()后: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
std::cout << "注意:不连续的重复元素不会被删除" << std::endl;
// 3. 先排序再使用unique(常用组合)
std::cout << "\n3. 先排序再使用unique(删除所有重复元素):" << std::endl;
std::list<int> list3 = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
std::cout << "初始list: ";
for (int n : list3) std::cout << n << " ";
std::cout << " 大小: " << list3.size() << std::endl;
list3.sort(); // 先排序
std::cout << "排序后: ";
for (int n : list3) std::cout << n << " ";
std::cout << std::endl;
list3.unique(); // 再删除重复元素
std::cout << "unique()后: ";
for (int n : list3) std::cout << n << " ";
std::cout << " 大小: " << list3.size() << std::endl;
// 4. 使用自定义比较函数(谓词)
std::cout << "\n4. 使用自定义比较函数:" << std::endl;
std::list<int> list4 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
std::cout << "初始list: ";
for (int n : list4) std::cout << n << " ";
std::cout << " 大小: " << list4.size() << std::endl;
// 自定义比较:如果两个数相差不超过1,则认为相等
list4.unique([](int a, int b) { return std::abs(a - b) <= 1; });
std::cout << "自定义比较unique后: ";
for (int n : list4) std::cout << n << " ";
std::cout << " 大小: " << list4.size() << std::endl;
std::cout << "注意:相邻且相差不超过1的元素被删除了" << std::endl;
// 5. 字符串list的去重
std::cout << "\n5. 字符串list的去重:" << std::endl;
std::list<std::string> words = {"apple", "apple", "banana", "banana", "apple", "cherry"};
std::cout << "初始字符串list: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
// 先排序再去重
words.sort();
std::cout << "排序后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << std::endl;
words.unique();
std::cout << "unique()后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << " 大小: " << words.size() << std::endl;
// 6. 自定义字符串比较(忽略大小写)
std::cout << "\n6. 自定义字符串比较(忽略大小写):" << std::endl;
std::list<std::string> list5 = {"Apple", "apple", "BANANA", "banana", "Cherry"};
std::cout << "初始list: ";
for (const auto& w : list5) std::cout << w << " ";
std::cout << " 大小: " << list5.size() << std::endl;
// 排序(默认区分大小写)
list5.sort();
std::cout << "排序后: ";
for (const auto& w : list5) std::cout << w << " ";
std::cout << std::endl;
// 自定义比较:比较小写形式是否相等
list5.unique([](const std::string& a, const std::string& b) {
std::string a_lower, b_lower;
for (char c : a) a_lower += std::tolower(c);
for (char c : b) b_lower += std::tolower(c);
return a_lower == b_lower;
});
std::cout << "忽略大小写unique后: ";
for (const auto& w : list5) std::cout << w << " ";
std::cout << " 大小: " << list5.size() << std::endl;
// 7. 实际应用:删除连续相同的字符
std::cout << "\n7. 实际应用:删除连续相同的字符:" << std::endl;
std::list<char> letters = {'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'e', 'e', 'e'};
std::cout << "初始字符list: ";
for (char c : letters) std::cout << c << " ";
std::cout << " 大小: " << letters.size() << std::endl;
letters.unique();
std::cout << "unique()后: ";
for (char c : letters) std::cout << c << " ";
std::cout << " 大小: " << letters.size() << std::endl;
std::cout << "只保留了每组相同字符的第一个" << std::endl;
return 0;
}

5.5. merge(合并)
作用:将两个已排序的 list 合并成一个有序的 list。合并后,源 list 变为空。
前提条件:两个 list 都必须已经按照相同的排序规则(升序)排好序。
特点:
- 合并操作是稳定的(相等元素的相对顺序保持不变)。
- 非常高效,时间复杂度为 O(n),因为只需重新链接节点。
- 有重载版本可以接受自定义的比较函数。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== merge方法示例 ===" << std::endl;
// 1. 合并两个升序排列的list
std::cout << "\n1. 合并两个升序排列的list:" << std::endl;
std::list<int> list1 = {1, 3, 5, 7, 9};
std::list<int> list2 = {2, 4, 6, 8, 10};
std::cout << "合并前:" << std::endl;
std::cout << "list1: ";
for (int n : list1) std::cout << n << " ";
std::cout << " 大小: " << list1.size() << std::endl;
std::cout << "list2: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
list1.merge(list2); // 合并list2到list1
std::cout << "\n合并后:" << std::endl;
std::cout << "list1: ";
for (int n : list1) std::cout << n << " ";
std::cout << " 大小: " << list1.size() << std::endl;
std::cout << "list2: ";
for (int n : list2) std::cout << n << " ";
std::cout << " 大小: " << list2.size() << std::endl;
// 2. 合并包含重复元素的list
std::cout << "\n2. 合并包含重复元素的list:" << std::endl;
std::list<int> list3 = {1, 2, 2, 5, 9};
std::list<int> list4 = {2, 3, 4, 6, 7};
std::cout << "合并前:" << std::endl;
std::cout << "list3: ";
for (int n : list3) std::cout << n << " ";
std::cout << std::endl;
std::cout << "list4: ";
for (int n : list4) std::cout << n << " ";
std::cout << std::endl;
list3.merge(list4);
std::cout << "\n合并后:" << std::endl;
std::cout << "list3: ";
for (int n : list3) std::cout << n << " ";
std::cout << " 大小: " << list3.size() << std::endl;
std::cout << "list4: ";
for (int n : list4) std::cout << n << " ";
std::cout << " 大小: " << list4.size() << std::endl;
// 3. 自定义比较函数(降序合并)
std::cout << "\n3. 自定义比较函数(降序合并):" << std::endl;
std::list<int> list5 = {9, 7, 5, 3, 1}; // 降序排列
std::list<int> list6 = {10, 8, 6, 4, 2}; // 降序排列
std::cout << "合并前:" << std::endl;
std::cout << "list5(降序): ";
for (int n : list5) std::cout << n << " ";
std::cout << std::endl;
std::cout << "list6(降序): ";
for (int n : list6) std::cout << n << " ";
std::cout << std::endl;
// 使用自定义比较函数进行降序合并
list5.merge(list6, std::greater<int>());
std::cout << "\n降序合并后:" << std::endl;
std::cout << "list5: ";
for (int n : list5) std::cout << n << " ";
std::cout << " 大小: " << list5.size() << std::endl;
std::cout << "list6: ";
for (int n : list6) std::cout << n << " ";
std::cout << " 大小: " << list6.size() << std::endl;
// 4. 字符串list的合并
std::cout << "\n4. 字符串list的合并:" << std::endl;
std::list<std::string> words1 = {"apple", "banana", "orange"};
std::list<std::string> words2 = {"grape", "kiwi", "peach"};
std::cout << "合并前:" << std::endl;
std::cout << "words1: ";
for (const auto& w : words1) std::cout << w << " ";
std::cout << std::endl;
std::cout << "words2: ";
for (const auto& w : words2) std::cout << w << " ";
std::cout << std::endl;
// 注意:字符串默认按字典序排序
words1.sort();
words2.sort();
std::cout << "\n排序后:" << std::endl;
std::cout << "words1: ";
for (const auto& w : words1) std::cout << w << " ";
std::cout << std::endl;
std::cout << "words2: ";
for (const auto& w : words2) std::cout << w << " ";
std::cout << std::endl;
words1.merge(words2);
std::cout << "\n合并后:" << std::endl;
std::cout << "words1: ";
for (const auto& w : words1) std::cout << w << " ";
std::cout << " 大小: " << words1.size() << std::endl;
std::cout << "words2: ";
for (const auto& w : words2) std::cout << w << " ";
std::cout << " 大小: " << words2.size() << std::endl;
// 5. 错误的用法:合并未排序的list
std::cout << "\n5. 错误的用法:合并未排序的list:" << std::endl;
std::list<int> list7 = {5, 1, 9, 3, 7}; // 未排序
std::list<int> list8 = {2, 8, 4, 6, 10}; // 未排序
std::cout << "合并前:" << std::endl;
std::cout << "list7(未排序): ";
for (int n : list7) std::cout << n << " ";
std::cout << std::endl;
std::cout << "list8(未排序): ";
for (int n : list8) std::cout << n << " ";
std::cout << std::endl;
list7.merge(list8); // 合并未排序的list,结果可能不正确
std::cout << "\n合并后:" << std::endl;
std::cout << "list7: ";
for (int n : list7) std::cout << n << " ";
std::cout << " 大小: " << list7.size() << std::endl;
std::cout << "注意:合并未排序的list可能导致结果不正确" << std::endl;
// 6. 合并空list
std::cout << "\n6. 合并空list:" << std::endl;
std::list<int> list9 = {1, 2, 3, 4, 5};
std::list<int> emptyList;
std::cout << "合并前:" << std::endl;
std::cout << "list9: ";
for (int n : list9) std::cout << n << " ";
std::cout << " 大小: " << list9.size() << std::endl;
std::cout << "emptyList: ";
for (int n : emptyList) std::cout << n << " ";
std::cout << " 大小: " << emptyList.size() << std::endl;
list9.merge(emptyList); // 合并空list
std::cout << "\n合并后:" << std::endl;
std::cout << "list9: ";
for (int n : list9) std::cout << n << " ";
std::cout << " 大小: " << list9.size() << std::endl;
std::cout << "emptyList: ";
for (int n : emptyList) std::cout << n << " ";
std::cout << " 大小: " << emptyList.size() << std::endl;
std::cout << "合并空list不会改变原list" << std::endl;
return 0;
}


5.6. sort(排序)
作用:对容器内的元素进行排序。由于 list 不能随机访问,它使用归并排序(或其他适合链表的算法)来实现。
特点:
- 排序是稳定的。
- 时间复杂度为 O(n log n)。
- 会改变容器本身(就地排序)。
- 有重载版本可以接受自定义的比较函数。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== list的sort方法示例 ===" << std::endl;
// 1. 默认升序排序
std::cout << "\n1. 默认升序排序:" << std::endl;
std::list<int> numbers = {5, 2, 8, 1, 9, 3, 7, 4, 6, 10};
std::cout << "排序前: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
numbers.sort(); // 默认升序排序
std::cout << "排序后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 2. 降序排序
std::cout << "\n2. 降序排序:" << std::endl;
std::list<int> list2 = {5, 2, 8, 1, 9, 3, 7, 4, 6, 10};
std::cout << "排序前: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
list2.sort(std::greater<int>()); // 降序排序
std::cout << "降序排序后: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
// 3. 字符串排序
std::cout << "\n3. 字符串排序:" << std::endl;
std::list<std::string> words = {"banana", "apple", "cherry", "date", "elderberry"};
std::cout << "排序前: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << std::endl;
words.sort(); // 默认按字典序排序
std::cout << "排序后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << std::endl;
// 4. 自定义排序规则(按字符串长度排序)
std::cout << "\n4. 按字符串长度排序:" << std::endl;
std::list<std::string> list3 = {"apple", "banana", "cherry", "date", "fig", "grapefruit"};
std::cout << "排序前: ";
for (const auto& w : list3) std::cout << w << " ";
std::cout << std::endl;
// 自定义比较函数:按长度排序,长度相同按字典序
list3.sort([](const std::string& a, const std::string& b) {
if (a.length() != b.length())
return a.length() < b.length();
return a < b;
});
std::cout << "按长度排序后: ";
for (const auto& w : list3) std::cout << w << " ";
std::cout << std::endl;
// 5. 结构体排序
std::cout << "\n5. 结构体排序:" << std::endl;
struct Person {
std::string name;
int age;
double salary;
};
std::list<Person> people = {
{"Alice", 30, 50000},
{"Bob", 25, 45000},
{"Charlie", 35, 60000},
{"David", 28, 48000},
{"Eve", 40, 70000}
};
std::cout << "排序前:" << std::endl;
for (const auto& p : people) {
std::cout << p.name << " (" << p.age << "岁, 工资: " << p.salary << ")" << std::endl;
}
// 按年龄排序
people.sort([](const Person& a, const Person& b) {
return a.age < b.age;
});
std::cout << "\n按年龄排序后:" << std::endl;
for (const auto& p : people) {
std::cout << p.name << " (" << p.age << "岁, 工资: " << p.salary << ")" << std::endl;
}
// 按工资降序排序
people.sort([](const Person& a, const Person& b) {
return a.salary > b.salary;
});
std::cout << "\n按工资降序排序后:" << std::endl;
for (const auto& p : people) {
std::cout << p.name << " (" << p.age << "岁, 工资: " << p.salary << ")" << std::endl;
}
return 0;
}


5.7. reverse(反转)
作用:将容器中元素的顺序反转。
特点:
- 非常高效,时间复杂度为 O(n),因为只需将每个节点的前后指针交换。
- 会改变容器本身。
cpp
#include <iostream>
#include <list>
int main() {
std::cout << "=== list的reverse方法示例 ===" << std::endl;
// 1. 反转整数list
std::cout << "\n1. 反转整数list:" << std::endl;
std::list<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << "反转前: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
numbers.reverse(); // 反转list
std::cout << "反转后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 2. 反转字符串list
std::cout << "\n2. 反转字符串list:" << std::endl;
std::list<std::string> words = {"apple", "banana", "cherry", "date", "elderberry"};
std::cout << "反转前: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << std::endl;
words.reverse(); // 反转list
std::cout << "反转后: ";
for (const auto& w : words) std::cout << w << " ";
std::cout << std::endl;
// 3. 反转单个元素的list
std::cout << "\n3. 反转单个元素的list:" << std::endl;
std::list<int> single = {42};
std::cout << "反转前: ";
for (int n : single) std::cout << n << " ";
std::cout << std::endl;
single.reverse();
std::cout << "反转后: ";
for (int n : single) std::cout << n << " ";
std::cout << std::endl;
// 4. 反转空list
std::cout << "\n4. 反转空list:" << std::endl;
std::list<int> emptyList;
std::cout << "反转前: ";
for (int n : emptyList) std::cout << n << " ";
std::cout << "(空list)" << std::endl;
emptyList.reverse(); // 反转空list是安全的
std::cout << "反转后: ";
for (int n : emptyList) std::cout << n << " ";
std::cout << "(空list)" << std::endl;
// 5. 多次反转
std::cout << "\n5. 多次反转:" << std::endl;
std::list<int> list2 = {1, 2, 3, 4, 5};
std::cout << "原始: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
list2.reverse();
std::cout << "第一次反转: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
list2.reverse();
std::cout << "第二次反转: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
list2.reverse();
std::cout << "第三次反转: ";
for (int n : list2) std::cout << n << " ";
std::cout << std::endl;
// 6. 反转和排序结合使用
std::cout << "\n6. 反转和排序结合使用:" << std::endl;
std::list<int> list3 = {5, 3, 8, 1, 9, 2, 7, 4, 6, 10};
std::cout << "原始: ";
for (int n : list3) std::cout << n << " ";
std::cout << std::endl;
// 先排序
list3.sort();
std::cout << "排序后: ";
for (int n : list3) std::cout << n << " ";
std::cout << std::endl;
// 再反转(变成降序)
list3.reverse();
std::cout << "反转后(降序): ";
for (int n : list3) std::cout << n << " ";
std::cout << std::endl;
// 7. 自定义对象的反转
std::cout << "\n7. 自定义对象的反转:" << std::endl;
struct Point {
int x, y;
};
std::list<Point> points = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
std::cout << "反转前:" << std::endl;
for (const auto& p : points) {
std::cout << "(" << p.x << ", " << p.y << ") ";
}
std::cout << std::endl;
points.reverse();
std::cout << "反转后:" << std::endl;
for (const auto& p : points) {
std::cout << "(" << p.x << ", " << p.y << ") ";
}
std::cout << std::endl;
return 0;
}

