跳到主要内容
C++ STL list 容器常用接口与拓展用法详解 | 极客日志
C++ 算法
C++ STL list 容器常用接口与拓展用法详解 综述由AI生成 C++ STL list 容器基于双向链表实现,元素非连续存储。介绍其核心特性(动态分配、O(1) 插入删除)、常用接口(构造、容量、迭代器、遍历、增删改查)及拓展接口(emplace_back、merge、unique、splice、sort)。通过示例代码演示了 list 在内存管理、排序及合并操作中的具体应用,帮助开发者高效使用标准库容器。
DockerOne 发布于 2026/3/30 更新于 2026/5/23 25 浏览1、list 简介
在 C++ 标准库中,std::list 是一个双向链表容器。定义在头文件 <list> 中,它的元素在内存中不是连续存储的,而是通过节点之间的指针相互链接,这使得它在插入和删除操作上有独特的优势。
std::list 是一个双向链表容器,即其底层结构为双向链表(带头双向循环链表),需要注意,双向链表的头节点(哨兵位)只用来占位,而不存储有效数据。所以,双向链表的头插即是在 d1 节点之前插入节点;头删即删除 d1 节点;尾插即在 d3 节点之后插入节点;尾删即删除 d3 节点。
核心特性
双向链表结构 :每个元素包含前驱和后继指针,支持双向遍历
动态内存分配 :元素分散存储,无需预先分配固定大小的内存
高效的插入删除 :在任意位置插入 / 删除元素的时间复杂度为 O(1)(已知位置时)
不支持随机访问 :访问特定元素需要从头 / 尾遍历,时间复杂度为 O(n)
2、常用接口介绍
2.1、list 类对象的常用构造
实现 list 对象在定义的同时初始化。
构造函数(construct) 功能 list()默认构造,构造空链表(即哨兵位) list(const list<value_type>& lt)拷贝构造,用已经存在的对象 lt 初始化 list(size_t n, const value_type& val=value_type())填充构造函数,用 n 个 value_type 类型的值去初始化 list(InputIterator first,InputIterator last)迭代器区间构造,使用迭代器范围 [first, last) 内的元素来初始化 list 对象 list(std::initializer_list<value_type> ilist)初始化列表构造函数(C++11 引入)
void test1 () {
list<int > lt1;
list<int > lt2 (5 , 1 ) ;
list<int > lt3 (lt2) ;
;
;
}
list<int > lt4 (lt2. begin(), lt2. end())
list<int > lt5 ({ 1 ,2 ,3 ,4 ,5 })
2.2、list 对象容量操作 函数 功能 size()获取双向链表的有效节点个数 empty()判断链表是否为空
void test2 () {
list<int > lt ({ 1 ,2 ,3 ,4 ,5 }) ;
cout << lt.size () << endl;
if (lt.empty ()) cout << "为空" << endl;
else cout << "非空" << endl;
}
2.3、list iterator(迭代器) 此处,大家可暂时将迭代器理解成一个指针,该指针指向 list 中的某个节点。
函数 功能 lt.begin()begin 获取头节点下一个节点的迭代器(地址) lt.end()end 获取头节点的迭代器(地址) lt.rbegin()rbegin() 返回的是反向迭代器,指向链表的头节点 lt.rend()rend 获取头节点下一个节点的迭代器(地址)
2.4、链表的增删查改 函数 功能 front获取第一个节点的值 back获取最后一个节点的值 push_front(const value_type x)在头部插入值为 x 的新节点 pop_front删除头部节点 push_back(const value_type x)在尾部插入一个值为 x 的新节点 pop_back删除尾部节点 insert(iterator pos, const value_type x)在 pos 指向的节点之前插入一个值为 x 的新节点 erase(iterator pos)删除 pos 指向的节点 swap交换两个对象的值 clear清理链表中的有效节点
2.5、链表的遍历 由于 list 底层结构为双向链表,导致他的元素在内存中并不是连续存储的,所以我们不能用下标的方式来访问。
void test3 () {
list<int > lt ({ 1 ,2 ,3 ,4 ,5 }) ;
for (auto e : lt) {
cout << e << " " ;
}
}
void test4 () {
list<int > lt ({ 1 ,2 ,3 ,4 ,5 }) ;
list<int >::iterator it = lt.begin ();
while (it != lt.end ()) {
cout << *it << " " ;
it++;
}
}
3、拓展接口说明
3.1、尾插——emplace_back 前面我们已经介绍了一个尾插的接口(push_back),那为什么 list 容器还要实现一个 emplace_back 尾插接口呢?
假设我们额外定义一个 AA 类,然后,将 AA 类型的数据分别使用 push_back 和 emplace_back 尾插到 lt 对象,看会发生什么?
struct AA {
AA (int a1 = 1 , int a2 = 1 ) :_a1(a1) ,_a2(a2) {}
int _a1;
int _a2;
};
void test5 () {
AA a1;
list<AA> lt;
lt.push_back (a1);
lt.push_back (AA (20 , 20 ));
lt.push_back (30 , 30 );
}
这里有一种应用 emplace_back 特殊情景,此时只有 emplace_back 才能够实现。当我们想要直接将构造 a 对象的数据作为参数传给尾插函数时,push_back 就会报错,而 emplace_back 则支持这种操作。
void test6 () {
list<AA> lt;
lt.emplace_back (30 , 30 );
}
3.2、合并两个已排序的链表——merge 需要注意:merge 只能用来合并两个已经排好序的链表,同时,合并之后一个链表将会为空。
void test7 () {
std::list<double > first, second;
first.push_back (3.1 );
first.push_back (2.2 );
first.push_back (2.9 );
second.push_back (3.7 );
second.push_back (7.1 );
second.push_back (1.4 );
first.sort ();
second.sort ();
first.merge (second);
for (auto e : first) cout << e << " " ;
}
3.3、移除链表中连续的重复元素——unique void test8 () {
list<int > lt;
lt.push_back (1 );
lt.push_back (5 );
lt.push_back (5 );
lt.push_back (4 );
lt.push_back (5 );
lt.push_back (6 );
for (auto e : lt) cout << e << " " ;
cout << endl;
lt.unique ();
for (auto e : lt) cout << e << " " ;
}
3.4、将一个链表的元素或元素范围移动到另一个链表的指定位置——splice void test9 () {
std::list<int > mylist1, mylist2;
std::list<int >::iterator it;
for (int i = 1 ; i <= 4 ; ++i) mylist1. push_back (i);
for (int i = 1 ; i <= 3 ; ++i) mylist2. push_back (i * 10 );
it = mylist1. begin ();
++it;
mylist1. splice (it, mylist2);
for (auto e : mylist1) {
cout << e << " " ;
}
}
3.5、链表元素的排序——sort 我们知道 C++ 在标准库中已经实现了排序算法,为什么 list 还要再自己实现呢?这就是因为迭代器的性质造成的。下面我们来介绍一下迭代器的类型。
根据前面对 string 和 vector 的学习,我们知道,根据迭代器的功能,将迭代器分为:
iterator————普通对象
const_iterator————const 对象
reverse_iterator————普通对象的反向迭代器
const_reverse_iterator————const 对象的反向迭代器
按性质分为:(向上兼容)
随机迭代器:string/vector/deque... 支持++ / -- / + / - ;
双向迭代器:list/map/set... 支持++ / -- ;
单向迭代器:forward_list/unordered_map 支持++
#include <algorithm>
void test01 () {
list<int > lt;
lt.push_back (6 );
lt.push_back (3 );
lt.push_back (5 );
lt.push_back (2 );
lt.push_back (1 );
string st ("ahdncxvjsvf" ) ;
sort (st.begin (), st.end ());
cout << st << endl;
reverse (lt.begin (), lt.end ());
reverse (st.begin (), st.end ());
}
void test02 () {
list<int > lt;
lt.push_back ({6 , 3 , 5 , 2 , 1 });
lt.sort ();
for (auto e : lt) cout << e << " " ;
}
4、总结 list 容器提供了丰富而且非常实用的接口,只要我们不断查文档,并不断应用,就一定能够掌握这些接口的用法。
相关免费在线工具 加密/解密文本 使用加密算法(如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