欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > C++ 算法(2):STL list 完全解析,从入门到高效使用

C++ 算法(2):STL list 完全解析,从入门到高效使用

2025/4/19 11:57:07 来源:https://blog.csdn.net/2501_91516851/article/details/147190988  浏览:    关键词:C++ 算法(2):STL list 完全解析,从入门到高效使用

1. list概述

std::list是C++标准模板库(STL)中的一个双向链表容器。与vectordeque不同,list不支持随机访问,但它在任何位置插入和删除元素都非常高效,时间复杂度为O(1)。

2. list的基本特性

  • 双向链表结构:每个元素都包含指向前驱和后继的指针

  • 高效插入删除:在任意位置插入/删除元素都很快

  • 不支持随机访问:不能像数组一样通过下标直接访问元素

  • 额外的内存开销:每个元素需要存储前后指针

3. 基本用法

3.1 包含头文件和声明

#include <list>// 声明一个int类型的list
std::list<int> myList;// 声明并初始化
std::list<int> initList = {1, 2, 3, 4, 5};

3.2 常用构造函数

std::list<int> l1;             // 空list
std::list<int> l2(5);          // 包含5个元素,每个都是0
std::list<int> l3(5, 10);      // 包含5个元素,每个都是10
std::list<int> l4(l3);         // 拷贝构造
std::list<int> l5(l4.begin(), l4.end()); // 范围构造

4. 常用操作

4.1 元素访问

std::list<int> nums = {1, 2, 3, 4, 5};// 访问首尾元素
std::cout << "第一个元素: " << nums.front() << std::endl;
std::cout << "最后一个元素: " << nums.back() << std::endl;// 注意:list没有operator[]和at()方法,不能随机访问

4.2 添加元素

std::list<int> nums;// 在末尾添加
nums.push_back(10);
nums.emplace_back(20);  // C++11, 更高效// 在开头添加
nums.push_front(5);
nums.emplace_front(1);  // C++11, 更高效// 在指定位置插入
auto it = nums.begin();
advance(it, 2);  // 将迭代器移动到第3个位置
nums.insert(it, 15);

4.3 删除元素

std::list<int> nums = {1, 2, 3, 4, 5};// 删除首尾元素
nums.pop_front();
nums.pop_back();// 删除指定位置的元素
auto it = nums.begin();
advance(it, 1);  // 移动到第2个元素
nums.erase(it);   // 删除该元素// 删除所有值为3的元素
nums.remove(3);// 删除满足条件的元素
nums.remove_if([](int n) { return n > 4; });  // 删除大于4的元素

4.4 大小和容量

std::list<int> nums = {1, 2, 3};std::cout << "大小: " << nums.size() << std::endl;
std::cout << "是否为空: " << (nums.empty() ? "是" : "否") << std::endl;
nums.resize(5);     // 将大小改为5,新增元素为0
nums.resize(2);     // 将大小改为2,删除多余元素

5. 迭代器操作

std::list<int> nums = {1, 2, 3, 4, 5};// 正向遍历
for (auto it = nums.begin(); it != nums.end(); ++it) {std::cout << *it << " ";
}
std::cout << std::endl;// 反向遍历
for (auto it = nums.rbegin(); it != nums.rend(); ++it) {std::cout << *it << " ";
}
std::cout << std::endl;// C++11范围for循环
for (int num : nums) {std::cout << num << " ";
}
std::cout << std::endl;

6. 特殊操作

6.1 排序

std::list<int> nums = {5, 3, 1, 4, 2};// 升序排序
nums.sort();// 降序排序
nums.sort(std::greater<int>());// 自定义排序
nums.sort([](int a, int b) {return a % 3 < b % 3;  // 按模3的结果排序
});

6.2 合并和拼接

std::list<int> list1 = {1, 3, 5};
std::list<int> list2 = {2, 4, 6};// 合并两个已排序的list
list1.sort();
list2.sort();
list1.merge(list2);  // list1现在包含1,2,3,4,5,6,list2为空// 拼接list
std::list<int> list3 = {7, 8, 9};
list1.splice(list1.end(), list3);  // 将list3的所有元素移动到list1末尾

6.3 去重

std::list<int> nums = {1, 2, 2, 3, 3, 3, 4};nums.unique();  // 删除连续的重复元素,结果为1,2,3,4// 自定义去重条件
nums.unique([](int a, int b) {return abs(a - b) < 2;  // 如果两元素差值小于2,视为相同
});

7. 性能考虑

  • 插入/删除:O(1)时间复杂度

  • 访问元素:O(n)时间复杂度,需要遍历

  • 排序:list有内置的sort方法,比通用算法std::sort更高效,因为它利用了链表特性

  • 内存:每个元素需要额外存储两个指针,内存开销比vector大

8. 适用场景

  • 需要频繁在中间位置插入/删除元素

  • 不需要随机访问元素

  • 需要频繁对容器进行排序、合并等操作

  • 元素较大,移动成本高(因为list不需要像vector那样重新分配内存和移动元素)

9. 示例代码

#include <iostream>
#include <list>
#include <algorithm>int main() {// 创建并初始化liststd::list<int> numbers = {7, 5, 16, 8};// 添加元素numbers.push_back(25);numbers.push_front(3);// 插入元素auto it = numbers.begin();std::advance(it, 2);numbers.insert(it, 10);// 删除元素numbers.remove(16);  // 删除所有值为16的元素// 遍历liststd::cout << "List内容: ";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;return 0;
}

10. 总结

std::list是C++中一个强大的双向链表容器,特别适合需要频繁插入删除但不需要随机访问的场景。它提供了丰富的成员函数来操作链表,包括排序、合并、去重等特殊操作。正确使用list可以显著提高程序的效率,特别是在处理大型数据集时。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词