C++ list 带头双向链表增删查改模拟实现
前言:List 与 Vector、String 的差异
在深入实现之前,先明确一下 list 与其他容器的区别。相对于 string 和 vector,list 的实现要复杂一些,主要体现在以下几个方面:
- 没有重载运算符
[]:vector和string底层是数组或类似结构,访问效率高,所以支持随机访问。而list是链表结构,不支持随机访问,效率低,因此主要依赖迭代器。 - 没有
reserve接口:扩容插入数据时,vector可能一次插入多个,而list每次只能插入一个节点,不需要预分配连续空间。 - 特有的接口:
sort():排序(底层使用归并排序)。注意,STL 算法库中的通用排序通常依赖迭代器相减,但list的迭代器不支持该操作,所以list内部实现了自己的sort。性能上,数据量大时建议直接使用list::sort,而非调用算法库再复制。merge():归并(要求两个有序链表)。unique():去重(要求有序)。remove()/remove_if():删除指定值或满足条件的元素。splice():接合,将一个list的数据移动到另一个list中,不拷贝数据。
- 迭代器的不同:
vector和string使用原生指针作为迭代器即可满足核心功能(解引用、自增)。但list底层节点不连续,不能直接用原生指针,必须对迭代器进行包装,重载运算符以满足核心功能。
一、底层结构:节点与哨兵位
1. 节点构造
节点结构与数据结构课程中的双向链表一致,包含三个部分:节点数据、下一个节点 (next)、上一个节点 (prev)。

命名规范:尽量与标准库保持一致,方便后续在其他类中使用
typedef。struct vs class:这里使用
struct包装而未使用class,是因为 C++ 中struct默认成员公有。若用class,访问私有成员需友元或 Getter 函数,过于繁琐。后续如需调整权限,可通过typedef配合访问限定符处理。
2. 带头双向链表验证
通过观察 SGI 库中 list 的成员变量和构造函数,可以发现其底层是一个带头双向链表。构造函数会构造出一个头尾相连的节点,即所谓的'哨兵位'(Sentinel Node),用于简化边界处理。

















