1. STL list 容器概述
list 是 C++ 标准模板库(STL)中的一个双向链表 容器。与 vector 或 deque 不同,list 在任意位置的插入和删除操作效率更高,但随机访问效率较低。
核心特性:
- 双向链表结构(每个节点包含前驱和后继指针)
- 动态内存分配,节点独立存储
- 插入/删除时间复杂度:O(1)(已知位置)
- 随机访问时间复杂度:O(n)
2. list 的基本使用
常用操作示例
cpp
#include <iostream>
#include <list>
int main() {
// 初始化
std::list<int> lst = {1, 2, 3};
// 插入元素
lst.push_back(4); // 尾部插入
lst.push_front(0); // 头部插入
auto it = lst.begin();
std::advance(it, 2); // 移动迭代器
lst.insert(it, 10); // 在位置2插入10
// 删除元素
lst.pop_back(); // 删除尾部
lst.pop_front(); // 删除头部
lst.erase(it); // 删除迭代器指向元素
// 遍历
for (int num : lst) {
std::cout << num << " ";
}
// 输出:2 10 3
return 0;
}
3. 手撕模拟实现 list
核心结构设计
cpp
template <typename T>
class List {
private:
struct ListNode {
T data;
ListNode* prev;
ListNode* next;
ListNode(const T& val, ListNode* p = nullptr, ListNode* n = nullptr)
: data(val), prev(p), next(n) {}
};
ListNode* head; // 哨兵头节点
ListNode* tail; // 哨兵尾节点
size_t size;
public:
// 迭代器类
class Iterator {
private:
ListNode* current;
public:
Iterator(ListNode* node) : current(node) {}
T& operator*() { return current->data; }
Iterator& operator++() {
current = current->next;
return *this;
}
bool operator!=(const Iterator& other) const {
return current != other.current;
}
};
// 构造函数
List() : size(0) {
head = new ListNode(T());
tail = new ListNode(T());
head->next = tail;
tail->prev = head;
}
// 析构函数
~List() {
clear();
delete head;
delete tail;
}
void push_back(const T& val) {
ListNode* newNode = new ListNode(val, tail->prev, tail);
tail->prev->next = newNode;
tail->prev = newNode;
size++;
}
void pop_back() {
if (size == 0) return;
ListNode* last = tail->prev;
last->prev->next = tail;
tail->prev = last->prev;
delete last;
size--;
}
Iterator begin() { return Iterator(head->next); }
Iterator end() { return Iterator(tail); }
void clear() {
while (head->next != tail) {
pop_back();
}
}
};
4. 关键机制解析
-
哨兵节点
头尾哨兵节点(
head/tail)不存储数据,仅用于简化边界操作,如begin()指向head->next,end()指向tail。 -
迭代器设计
封装节点指针,通过重载
operator++和operator*实现链表遍历。 -
插入/删除逻辑
-
插入 :修改相邻节点的指针,例如
push_back中:cppnewNode->prev = tail->prev; // 新节点前驱指向原尾节点前驱 newNode->next = tail; // 新节点后继指向尾哨兵 tail->prev->next = newNode; // 原尾节点前驱的后继指向新节点 tail->prev = newNode; // 尾哨兵前驱指向新节点 -
删除 :调整相邻节点指针并释放内存(见
pop_back)。
-
5. 应用场景
- 频繁在任意位置插入/删除(如 LRU 缓存算法)
- 不需要随机访问的场景
- 实现队列(
std::queue默认基于deque,但可适配list)
总结
list 通过双向链表结构优化了插入删除效率,但牺牲了随机访问性能。理解其底层实现有助于在特定场景下合理选择容器,并加深对 STL 设计思想的理解。