目录
[一. 认识 list](#一. 认识 list)
[1.1 list 和 vector 的核心区别](#1.1 list 和 vector 的核心区别)
[1.1.1 对比总结:](#1.1.1 对比总结:)
[二. list 的使用](#二. list 的使用)
[2.1 list 的构造](#2.1 list 的构造)
[2.2 list 的迭代器](#2.2 list 的迭代器)
[2.2.1 迭代器的知识补充](#2.2.1 迭代器的知识补充)
[2.3 list 的其他函数接口](#2.3 list 的其他函数接口)
[2.4 list 的增删查改](#2.4 list 的增删查改)
[2.4.1 list 的增](#2.4.1 list 的增)
[2.4.1.1 push_back() 和 push_front()](#2.4.1.1 push_back() 和 push_front())
[2.4.1.2 insert](#2.4.1.2 insert)
[2.4.2 list 的删](#2.4.2 list 的删)
[2.4.2.1 pop_back() 和 pop_front()](#2.4.2.1 pop_back() 和 pop_front())
[2.4.2.2 erase](#2.4.2.2 erase)
[2.4.3 list 的查](#2.4.3 list 的查)
[2.5 其他常用的函数接口](#2.5 其他常用的函数接口)
[2.5.1 reverse](#2.5.1 reverse)
[2.5.2 sort](#2.5.2 sort)
[三. list 迭代器失效](#三. list 迭代器失效)
[四. initializer_list](#四. initializer_list)
[4.1 认识 initializer_list](#4.1 认识 initializer_list)
[4.2 代码示例:](#4.2 代码示例:)
[五. list 的实现](#五. list 的实现)
[5.1 list 的构造和赋值运算符重载](#5.1 list 的构造和赋值运算符重载)
[5.2 迭代器的实现](#5.2 迭代器的实现)
[5.3 list 的插入](#5.3 list 的插入)
[5.4 list 的删除](#5.4 list 的删除)
[5.5 析构、clear()](#5.5 析构、clear())
一. 认识 list
list 的本质是双向循环链表,且带有一个"哨兵位头结点"(不存储 有效数据),结构如下:

- 双向:每个字节包含前驱指针 (prev) 和后继指针 (next) ,支持向前,向后遍历;
- 循环:尾节点的 next 指向头结点,头结点的 prev 指向尾结点,形成闭环;
- 哨兵位头结点:避免插入/删除时判断"是否为空""是否为头结点"的麻烦,简化代码逻辑。
1.1 list 和 vector 的核心区别
| 对比项 | list(双向链表) |
vector(动态数组) |
|---|---|---|
| 底层结构 | 每个元素都是独立节点,通过 prev 和 next 指针连接,内存不连续 |
一块连续内存空间存储元素,类似可自动扩容的数组 |
| 插入/删除效率 | 已知迭代器位置时效率高,插入删除只需修改前后节点指针,时间复杂度 O(1) | 中间插入或删除需要移动后面的元素,时间复杂度 O(N);尾部插入平均 O(1) |
| 随机访问 | 不支持下标访问,需要从头或尾遍历寻找元素,时间复杂度 O(N) | 支持 operator[] 和 at(),可以根据下标直接定位,时间复杂度 O(1) |
| 迭代器特点 | 插入、删除节点后,其他元素的迭代器通常不会失效,只影响被删除节点 | 扩容时会重新分配内存,导致全部迭代器失效;非扩容插入会使插入位置之后的迭代器失效 |
| 空间利用 | 每个节点额外保存两个指针,内存开销较大;节点分散可能造成缓存不友好 | 存储空间连续,额外空间主要来自预留容量,缓存命中率更高 |
| 适用场景 | 频繁在任意位置插入、删除,并且不需要随机访问 | 需要大量访问元素、遍历数据、尾部添加元素 |
| 查找效率 | 查找必须遍历链表,时间复杂度 O(N) | 支持随机定位,但普通查找仍为 O(N) |
| 排序操作 | 有成员函数 sort(),利用链表结构避免大量移动元素 |
通常使用算法库 sort(),依靠连续内存获得更好的性能 |
1.1.1 对比总结:
如果程序主要进行中间位置频繁插入和删除 ,并且不经常通过下标访问,
list更合适。如果程序主要进行随机访问、遍历以及尾部插入 ,优先考虑
vector。实际开发中,
vector往往是默认选择,因为连续内存带来的缓存优势通常比链表的插入优势更明显。
二. list 的使用
2.1 list 的构造

| 构造函数 | 接口说明 | 代码示例 |
|---|---|---|
| list() | 构造空 list |
list<int> l1;(空链表,仅含头结点) |
| list(size_type n, const T& val = T()) | 构造包含 n 个 val 的 list |
list<int> l2(5, 3);(元素:3,3,3,3,3) |
| list(const list& x) | 拷贝构造 | list<int> l3(l2);(l3 是 l2 的副本) |
| list(InputIterator first, InputIterator last) | 使用 [first,last) 区间构造 |
int arr[] = {1,2,3}; list<int> l4(arr, arr+3);(元素:1,2,3) |
cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
list<int> a1;
Print_List(a1);
list<int> a2(3, 4);
Print_List(a2);
list<int> a3(a2);
Print_List(a3);
list<int> a4(a, a + sizeof(a) / sizeof(a[0]));
Print_List(a4);
return 0;
}
2.2 list 的迭代器
list 的迭代器使用和string、vector 几乎没有差别,这里就不再赘述。
cpp
#include <iostream>
using namespace std;
#include <list>
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
//正向遍历
auto it = dict.begin();
while (it != dict.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
//反向遍历
auto _it = dict.rbegin();
while (_it != dict.rend())
{
cout << *_it << ' ';
_it++;
}
cout << endl;
return 0;
}
2.2.1 迭代器的知识补充
迭代器可以按功能和性质划分:
**功能:**iterator、reverse_iterator、const_iterator、const_reverse_iterator。
**性质:单向:**forward_list / unordered_map..... ++
**双向:**list / map / set.... ++ / - -
**随机:**vector / string /deque.... ++ / - - / + / -
我们也可以在 cpluplus 网站上查看不同迭代器的性质:

2.3 list 的其他函数接口
list 也提供函数 size()、clear()、empty()、resize()。但是并没有提供 capacity()、reserve()、shrink_to_fit()。
| 函数声明 | 接口说明 | 代码示例(基于 l4 = {1,2,3,4}) |
|---|---|---|
| size() | 返回 list 中有效元素的个数,返回类型为无符号整数(size_type) |
l4.size();(返回 4,表示 l4 中有 4 个元素) |
| clear() | 清空 list 中的所有元素,执行后 size() 变为 0 |
l4.clear();(执行后 l4 变为空链表 {}) |
| empty() | 检测 list 是否为空,空返回 true,非空返回 false |
l4.empty();(返回 false,因为 l4 中有 4 个元素) |
| resize(size_type n, T val = T()) | 调整 list 中有效元素的个数;若 n > size(),新增元素并初始化为 val;若 n < size(),删除多余元素 |
l4.resize(6, 10);(修改后 l4 为 {1,2,3,4,10,10}) |
在访问元素方面,list 并没有重载 和 at(list 不支持随机访问),而是和 string、vector 一样提供 **front()、back()**访问首尾元素。
| 函数声明 | 接口说明 | 代码示例(基于 l4 = {1,2,3,4}) |
|---|---|---|
| front() | 返回 list 第一个元素的引用,可用于访问或修改首元素 |
l4.front();(返回第一个元素 1,也可以通过 l4.front() = 10; 修改) |
| back() | 返回 list 最后一个元素的引用,可用于访问或修改尾元素 |
l4.back();(返回最后一个元素 4,也可以通过 l4.back() = 20; 修改) |
2.4 list 的增删查改
2.4.1 list 的增
2.4.1.1 push_back() 和 push_front()
cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
dict.push_back(100);
dict.push_front(200);
Print_List(dict);
return 0;
}
2.4.1.2 insert

cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
dict.insert(dict.begin(), 100);
Print_List(dict);
dict.insert(dict.begin(),3, 11);
Print_List(dict);
dict.insert(dict.begin(), a, a + sizeof(a) / sizeof(a[0]));
Print_List(dict);
return 0;
}
2.4.2 list 的删
2.4.2.1 pop_back() 和 pop_front()
cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
dict.pop_back();
Print_List(dict);
dict.pop_front();
Print_List(dict);
return 0;
}
2.4.2.2 erase

cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
dict.erase(dict.begin());
Print_List(dict);
dict.erase(dict.begin(),--dict.end());
Print_List(dict);
return 0;
}
2.4.3 list 的查
list 和 vector 一样,只能使用标准库里的 find():

cpp
#include <iostream>
using namespace std;
#include <list>
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
list<int>::iterator it = find(dict.begin(), dict.end(), 10);
if (it != dict.end())
{
cout << "找到了" << *it << endl;
}
else
{
cout << "没找到" << endl;
}
return 0;
}
2.5 其他常用的函数接口
2.5.1 reverse

cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
Print_List(dict);
dict.reverse();
Print_List(dict);
return 0;
}
但是这个函数的实现有点多余,我们可以像 string、vector 一样使用标准库的 reverse():

而且我们发现标准库的 reverse() 要求至少是双向迭代器,不用担心 list 不能使用
cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
Print_List(dict);
reverse(dict.begin(), dict.end());
Print_List(dict);
return 0;
}
2.5.2 sort

标准库的 sort 要求迭代器至少是随机迭代器,那么 list 是使用不了的 。所以 list 自己实现了 sort

cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,4,3,7,5,10,50,8,40 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
Print_List(dict);
dict.sort();
Print_List(dict);
return 0;
}
三. list 迭代器失效
list 和 vector 不一样,insert 的时候迭代器不会失效,但是 erase 的时候会失效
cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,4,3,7,5,10,50,8,40 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
auto it = dict.begin();
dict.insert(it, -10);
Print_List(dict);
//迭代器并没有失效,仍然指向值为1的节点
dict.insert(it, 100);
Print_List(dict);
return 0;
}
cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
int a[] = { 1,4,3,7,5,10,50,8,40 };
list<int> dict(a, a + sizeof(a) / sizeof(a[0]));
auto it = dict.begin();
dict.erase(it);
Print_List(dict);
//值为1的节点被删除,it指向的位置被释放,迭代器失效
dict.erase(it);
Print_List(dict);
return 0;
}
四. initializer_list
在 C++11 中支持用 initializer_list 来构造 list:

4.1 认识 initializer_list

initializer_list 是 C++11 为
{}语法准备的中间桥梁,它本身不负责存数据,只保存编译器生成的临时数组的访问信息,让 vector、list、自定义类都能支持{1,2,3}这种初始化方式。
4.2 代码示例:
cpp
#include <iostream>
using namespace std;
#include <list>
template<class Container>
void Print_List( Container& con)
{
typename Container::iterator it = con.begin();
while (it != con.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
int main()
{
list<int> dict({ 1,2,3,4,5 });
Print_List(dict);
return 0;
}
initializer_list的构造过程是:当编译器遇到 {1,2,3} 这种初始化列表时,会先创建一个隐藏的 const 数组保存元素,然后构造一个 initializer_list 对象,让它保存数组的首地址和大小。initializer_list 本身不存储数据,只是对这块临时数组的只读访问,所以其中的元素不能修改。
cpp
#include <iostream>
#include <initializer_list>
using namespace std;
void Print(initializer_list<int> il)
{
for (auto e : il)
cout << e << " ";
}
int main()
{
initializer_list<int> il = {1, 2, 3};
Print({4, 5, 6});
}
大致过程:
cpp{1,2,3} ↓ 生成隐藏数组 const int temp[]{1,2,3} ↓ initializer_list保存temp地址和大小 ↓ 通过begin/end访问元素
五. list 的实现
5.1 list 的构造和赋值运算符重载
cpp
void empty_init()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
_size = 0;
}
list(initializer_list<T> il)
{
empty_init();
for (auto& e : il)
{
push_back(e);
}
}
list(const list<T>& It)
{
empty_init();
for (auto& it : It)
{
push_back(it);
}
}
void swap( list<T>& It)
{
std::swap(this->_head, It._head);
std::swap(this->_size, It._size);
}
list<T>& operator=( list<T> It)
{
swap(It);
return *this;
}
5.2 迭代器的实现
cpp
template<class T,class Ref,class Ptr>
struct list_iterator
{
typedef list_node<T> Node;
typedef list_iterator<T, Ref, Ptr> Self;
list_iterator(Node* node)
:_node(node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator--(int)
{
Self tmp = *this;
_node = _node->_prev;
return tmp;
}
Self operator++(int)
{
Self tmp = *this;
_node = _node->_next;
return tmp;
}
bool operator==(const Self& v)const
{
return _node == v._node;
}
bool operator!=(const Self& v)const
{
return _node != v._node;
}
Node* _node;
};
template<class T>
class list
{
typedef list_node<T> Node;
public:
typedef list_iterator<T, T&, T*> iterator;
typedef list_iterator< T, const T&, const T*> const_iterator;
iterator begin()
{
iterator it(_head->_next);
return it;
}
const_iterator begin()const
{
const_iterator it(_head->_next);
return it;
}
iterator end()
{
return iterator (_head);
}
const_iterator end()const
{
return const_iterator (_head);
}
private:
Node* _head;
size_t _size;
}
5.3 list 的插入
cpp
void push_back(const T& val )
{
Node* newnode = new Node(val);
newnode->_prev = _head->_prev;
newnode->_next = _head;
_head->_prev->_next = newnode;
_head->_prev = newnode;
_size++;
}
void push_front(const T& val)
{
insert(begin(), val);
}
iterator insert(iterator it, const T& x)
{
Node* newnode = new Node(x);
newnode->_prev = it._node->_prev;
newnode->_next = it._node;
it._node->_prev->_next = newnode;
it._node->_prev = newnode;
_size++;
return newnode;
}
5.4 list 的删除
cpp
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
iterator erase(iterator pos)
{
assert(pos != end());
iterator it = pos._node->_next;
pos._node->_prev->_next = pos._node->_next;
pos._node->_next->_prev = pos._node->_prev;
delete pos._node;
_size--;
return it;
}
5.5 析构、clear()
cpp
~list()
{
clear();
delete _head;
_head = nullptr;
}
void clear()
{
iterator it = begin();
while (it != end())
{
erase(it);
}
}