跳到主要内容
C++ STL 容器详解:双向链表 list 核心用法与注意事项 | 极客日志
C++ 算法
C++ STL 容器详解:双向链表 list 核心用法与注意事项 C++ STL 中的 list 是基于双向链表实现的序列容器,支持在任意位置高效插入和删除元素,时间复杂度为 O(1)。与 vector 不同,list 不支持随机访问且内存开销较大。本文详细解析了 list 的构造函数、迭代器使用规则、常用修改操作如 push_front/back、insert/erase 以及排序合并等成员函数。重点强调了迭代器失效问题及 reserve 方法不适用于 list 的特性,帮助开发者在实际项目中合理选型并避免常见陷阱。
灭霸 发布于 2026/3/30 更新于 2026/4/25 0 浏览C++ STL 容器详解:双向链表 list 核心用法与注意事项
list 简介
std::list 是 C++ 标准库中一个序列式容器,底层采用双向链表结构。这意味着每个元素(节点)都存储在独立的内存空间中,通过两个指针分别指向前后节点。
这种结构赋予了 list 在常数时间内于任意位置进行插入和删除操作的能力,时间复杂度为 O(1)。相比基于数组的 vector 或 deque,list 在处理频繁修改数据的场景下更具优势,无需移动大量元素。
主要特点:
优点 :高效的插入和删除;支持双向迭代(可从前向后,也可从后向前)。
缺点 :不支持随机访问(无法通过下标直接访问);每个节点需额外存储前后指针,内存开销略大。
与 forward_list(单向链表)不同,list 支持双向遍历,灵活性更高。
list 的使用
构造函数
list 提供了多种构造方式,适应不同的初始化需求:
默认构造 :创建一个空列表。
explicit list (const allocator_type& alloc = allocator_type()) ;
填充构造 :创建包含 n 个值为 val 的元素。
explicit list (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type()) ;
范围构造 :利用迭代器区间初始化。
template <class InputIterator >
list (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type ());
拷贝构造 :复制另一个 list 对象。
list (const list& x);
代码示例:
#include <iostream>
std;
{
list< > l1;
;
;
arr[] = { , , , , , , };
;
;
}
{
();
;
}
#include <list>
using
namespace
void test01 ()
int
list<int > l2 (6 , 6 )
list<int > l3 (l2. begin(), l2. end())
int
5
2
0
1
3
1
4
list<int > l4 (arr, arr + 7 )
list<int > l5 (l2)
int main ()
test01
return
0
特殊成员函数
析构函数 :对象销毁时自动调用,释放所有节点占用的内存。
赋值运算符重载 :执行深拷贝,确保新容器内部元素被正确复制。
迭代器的使用 获取迭代器通常使用 iterator 类型,它是 std::list 的内部定义类型。
正向遍历 :使用 begin() 和 end()。注意区间是左闭右开。
反向遍历 :使用 rbegin() 和 rend()。
虽然范围 for 循环语法简洁,但仅支持正向遍历。若需逆向操作,必须使用反向迭代器。
int arr[] = {5 , 2 , 0 , 1 , 3 , 1 , 4 };
list<int > l1 (arr, arr + 7 ) ;
list<int >::iterator it = l1. begin ();
while (it != l1. end ()) {
cout << *it << ' ' ;
it++;
}
cout << endl;
list<int >::reverse_iterator rit = l1. rbegin ();
while (rit != l1. rend ()) {
cout << *rit << ' ' ;
rit++;
}
cout << endl;
容器相关函数
size 和 empty
size():返回当前有效数据个数。
empty():判断容器是否为空。
list<int > l1;
list<int > l2 (6 , 6 ) ;
cout << "l1 size: " << l1. size () << endl;
cout << "l2 size: " << l2. size () << endl;
cout << "l1 empty: " << l1. empty () << endl;
cout << "l2 empty: " << l2. empty () << endl;
修改容器内容相关函数
push_front / emplace_front
push_front():在头部添加元素,涉及拷贝或移动。
emplace_front():在头部原地构造元素,避免拷贝,效率更高。
int arr[] = {5 , 2 , 0 , 1 , 3 , 1 , 4 };
int arr1[] = {1 , 3 , 1 , 4 , 5 , 2 , 0 };
list<int > l1 (arr, arr + 7 ) ;
list<int > l2 (arr1, arr1 + 7 ) ;
l1. emplace_front (6 );
l2. push_front (100 );
emplace_back / push_back l1. emplace_back (6 );
l2. push_back (100 );
insert / emplace
迭代器不失效 :insert 不会导致现有迭代器失效,仅修改链接关系。
功能 :支持插入单个元素、多个相同元素、或迭代器区间。
emplace :同 insert,但在指定位置直接构造元素。
int arr[] = {5 , 2 , 0 , 1 , 3 , 1 , 4 };
list<int > l3 (arr, arr + sizeof (arr) / sizeof (arr[0 ])) ;
list<int >::iterator pos = l3. begin ();
pos++;
l3. insert (pos, 0 );
l3. insert (pos, 5 , 6 );
list<int > lt4 (6 , 5 ) ;
l3. insert (pos, lt4. begin (), lt4. end ());
for (auto e : l3) {
cout << e << ' ' ;
}
cout << endl;
pop_front / pop_back
pop_front():删除头部元素。
pop_back():删除尾部元素。
list<int > l1;
l1. push_back (0 );
l1. push_back (1 );
l1. push_back (2 );
l1. push_back (3 );
for (auto e : l1) cout << e << ' ' ;
cout << endl;
l1. pop_back ();
l1. pop_back ();
for (auto e : l1) cout << e << ' ' ;
cout << endl;
erase / clear
erase :删除指定迭代器指向的节点。关键点 :被删除节点的迭代器会失效,但 erase 会返回下一个有效迭代器。务必使用返回值继续遍历。
clear :清空所有元素。
int arr[] = {5 , 2 , 0 , 1 , 3 , 1 , 4 };
list<int > l1 (arr, arr + sizeof (arr) / sizeof (arr[0 ])) ;
l1. erase (--l1. end ());
l1. clear ();
resize 调整容器大小。若缩小则截断多余部分;若扩大则尾插默认值或指定值。
list<int > l1 (5 , 3 ) ;
for (auto e : l1) cout << e << ' ' ;
cout << endl;
l1. resize (7 , 6 );
for (auto e : l1) cout << e << ' ' ;
cout << endl;
l1. resize (2 );
for (auto e : l1) cout << e << ' ' ;
cout << endl;
assign 替换容器内容。会先清空原数据,再根据传入参数(迭代器区间或值+数量)重新填充。
int arr[] = {5 , 2 , 0 , 1 , 3 , 1 , 4 };
list<int > l1 (arr, arr + 7 ) ;
list<int > l2;
l2. assign (l1. begin (), l1. end ());
for (auto e : l2) cout << e << ' ' ;
cout << endl;
swap 交换两个容器的内容,这是一个高效操作,仅交换内部指针,不涉及元素拷贝。
list<int > l1 (4 , 2 ) ;
list<int > l2 (4 , 6 ) ;
l1. swap (l2);
for (auto e : l1) cout << e << ' ' ;
cout << endl;
for (auto e : l2) cout << e << ' ' ;
cout << endl;
list 的相关操作函数
sort 对 list 进行排序。由于是双向链表,它使用内部归并排序,时间复杂度 O(n log n)。
list<int > lt;
lt.push_back (4 ); lt.push_back (7 ); lt.push_back (5 );
lt.push_back (9 ); lt.push_back (6 ); lt.push_back (0 ); lt.push_back (3 );
lt.sort ();
for (auto e : lt) cout << e << ' ' ;
cout << endl;
remove 移除所有等于指定值的元素。注意这是原地修改,匹配的是值而非迭代器。
list<int > lt;
lt.push_back (1 ); lt.push_back (4 ); lt.push_back (3 );
lt.push_back (3 ); lt.push_back (2 ); lt.push_back (2 ); lt.push_back (3 );
lt.remove (3 );
for (auto e : lt) cout << e << ' ' ;
cout << endl;
unique 删除连续的重复元素。因此通常需要先排序,否则非相邻的重复元素不会被删除。
lt.sort ();
lt.unique ();
for (auto e : lt) cout << e << ' ' ;
cout << endl;
merge 将两个已排序的 list 合并为一个。合并后源列表变为空,所有元素移至目标列表。要求两个列表均有序。
list<int > lt1;
lt1. push_back (3 ); lt1. push_back (8 ); lt1. push_back (1 );
list<int > lt2;
lt2. push_back (6 ); lt2. push_back (2 ); lt2. push_back (9 ); lt2. push_back (5 );
lt1. sort ();
lt2. sort ();
lt1. merge (lt2);
for (auto e : lt1) cout << e << ' ' ;
cout << endl;
reserve 注意 :std::list 不支持 reserve() 方法。因为链表内存是动态分散分配的,不存在连续内存块预分配的概念。该方法仅适用于 vector 等连续内存容器。
在实际开发中,选择 list 还是 vector 取决于具体场景。如果频繁在中间插入删除且不需要随机访问,list 是更好的选择;反之,若追求缓存友好性和顺序访问性能,vector 更优。理解这些底层差异,才能写出更健壮的 C++ 代码。
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online