C++ list 带头双向链表增删查改模拟实现
C++ list 容器基于带头双向链表的模拟实现。文章对比了 list 与 vector、string 的差异,重点讲解了迭代器的封装原理及 const 迭代器的实现。详细阐述了构造函数、析构函数、拷贝构造、赋值重载等接口逻辑,以及任意位置插入删除、尾插尾删、头插头删等操作的具体步骤。最后补充了迭代器 operator-> 重载及泛型打印容器的优化方案,完整展示了 C++ 标准库 list 的核心数据结构与功能模拟过程。

C++ list 容器基于带头双向链表的模拟实现。文章对比了 list 与 vector、string 的差异,重点讲解了迭代器的封装原理及 const 迭代器的实现。详细阐述了构造函数、析构函数、拷贝构造、赋值重载等接口逻辑,以及任意位置插入删除、尾插尾删、头插头删等操作的具体步骤。最后补充了迭代器 operator-> 重载及泛型打印容器的优化方案,完整展示了 C++ 标准库 list 的核心数据结构与功能模拟过程。

与 string、vector 相比,list 的实现相对复杂。主要差异如下:
sort():排序(底层使用归并排序),因 list 迭代器不支持随机访问减法操作,不能直接使用算法库 sort。merge():归并(针对两个有序带头双向链表)。unique():去重(针对有序带头双向链表)。remove():删除指定值的数据(不同于 erase 删除迭代器位置)。remove_if():配合仿函数删除满足条件的数据。splice():接合,将一个 list 中的数据移动到另一个 list,或调整当前 list 内部节点关系。节点包含三个变量:节点数据、下一个节点 (next)、上一个节点 (prev)。通常使用 struct 包装成员,默认公有,避免频繁使用友元。

list 底层为带头双向链表。构造函数中会构造出一个头尾相连的哨兵位节点,成员变量主要为指向该节点的指针。
迭代器分为输入、输出、前向、双向、随机访问等类型,支持的操作性质不同。

对于不能将原生指针作为迭代器的容器(如 list),需对迭代器进行包装。通常使用 struct 定义迭代器类,重载运算符以满足需求。
使用 struct 包装迭代器,对其使用的运算符进行重载。普通迭代器和 const 迭代器基本一致,区别在于解引用 (*) 和箭头 (->) 返回值的类型不同。
采用多模板参数方式解决返回值类型问题,避免代码冗余。注意迭代器本身不需要析构函数,它仅借用节点指针访问,销毁由 list 管理。

list 模拟标准库,提供头节点(哨兵位)和统计节点个数的变量 _size。通过迭代器访问接口,统一命名以屏蔽底层细节。

底层已实现,此处不再赘述。

无参构造创建只有哨兵位节点的双向链表,可复用 empty_init 函数实现。

清除数据但保留哨兵位节点。

复用 clear 函数清除数据,再释放哨兵位节点。

初始化哨兵位节点,将源数据尾插到新 list。

对于内置类型调用 std 库中的交换函数即可。

采用传值参数生成临时变量,再与待赋值变量互换,实现深拷贝效果。

依据 pos 节点和新节点 newnode 建立连接,更新前后节点指针,_size++。

注意哨兵位节点不能删除。保存待删除节点的前后节点,断开连接,释放节点,_size--。返回新的 pos 以避免迭代器失效。

直接复用任意位置插入、删除逻辑。

直接返回 _size 变量。

自定义类型无法直接通过 << 输出时,需在迭代器中重载 operator->() 函数。编译器优化了 -> 行为,实际调用 it.operator->()->_member。
struct AA {
AA(int a1 = 0, int a2 = 0) :_a1(a1), _a2(a2) {}
int _a1;
int _a2;
};
void test_list3() {
list<AA> lt;
lt.push_back(AA(1, 1));
lt.push_back(AA(2, 2));
lt.push_back(AA(3, 3));
list<AA>::iterator it = lt.begin();
while (it != lt.end()) {
cout << it->_a1 << " " << it->_a2 << endl;
++it;
}
cout << endl;
}
在模板中使用 typename 声明内嵌类型,确保编译器正确识别。
// 针对特定容器
// template<typename T> void print_list(const list<T>& lt) { ... }
// 泛型容器打印
template<typename Container>
void print_container(const Container& con) {
typename Container::const_iterator it = con.begin();
while (it != con.end()) {
cout << *it << " ";
++it;
}
cout << endl;
}

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online