0


【C++】从零实现 C++ 自定义 list 容器:双向链表与迭代器深度解析

个人主页: 起名字真南的CSDN博客

个人专栏:

  • 【数据结构初阶】 📘 基础数据结构
  • 【C语言】 💻 C语言编程技巧
  • 【C++】 🚀 进阶C++
  • 【OJ题解】 📝 题解精讲

目录


📌 1. 引言

在 C++ 中,STL

  1. list

容器提供了双向链表的实现,适用于需要频繁插入和删除的场景。本文将手把手带你实现一个自定义的

  1. list

容器,详细解析双向链表的节点设计、迭代器实现、增删操作等。希望通过本文的学习,你能对链表的底层原理有更深入的理解,并学会如何用 C++ 实现一个高效的

  1. list

容器。

📌 2. 内容概要

  • 双向链表的基本结构设计
  • 自定义迭代器的实现原理
  • 核心方法实现:push_backinserterase
  • 内存管理与析构函数
  • 性能分析与应用场景

📌 3.

  1. list

容器结构设计

✨ 3.1 节点结构设计

在双向链表中,每个节点包含数据域和两个指针域,分别指向前后节点。我们首先定义节点的结构体

  1. list_node

,用于存储数据和链接信息。

  1. template<classT>structlist_node{
  2. T _data;
  3. list_node<T>* _prev;
  4. list_node<T>* _next;list_node(const T& data =T()):_data(data),_prev(nullptr),_next(nullptr){}};
  • 代码解读: - _data:存储节点的数据。- _prev_next:分别指向前一个和后一个节点,形成双向链接。

✨ 3.2 自定义迭代器的实现

  1. list

容器需要一个迭代器来支持前向和后向遍历。我们设计一个

  1. list_iterator

,封装节点指针,并重载

  1. *

  1. ->

  1. ++

  1. --

等操作符。

  1. template<classT,classRef,classPtr>structlist_iterator{typedef list_node<T> Node;
  2. Node* _node;list_iterator(Node* node =nullptr):_node(node){}
  3. Ref operator*(){return _node->_data;}
  4. Ptr operator->(){return&_node->_data;}
  5. list_iterator&operator++(){ _node = _node->_next;return*this;}
  6. list_iterator operator++(int){ list_iterator tmp(*this); _node = _node->_next;return tmp;}
  7. list_iterator&operator--(){ _node = _node->_prev;return*this;}
  8. list_iterator operator--(int){ list_iterator tmp(*this); _node = _node->_prev;return tmp;}booloperator!=(const list_iterator& other)const{return _node != other._node;}booloperator==(const list_iterator& other)const{return _node == other._node;}};
  • 代码解读: - operator*operator->:分别返回节点的值和地址。- ++--:支持前后遍历。- ==!=:判断两个迭代器是否指向相同节点。

📌 4.

  1. list

容器的实现

✨ 4.1 核心成员函数

  • 构造函数:初始化一个空的链表,并设置头节点。
  • **push_backpush_front**:在链表尾部或头部插入元素。
  • **inserterase**:在指定位置插入或删除元素。
  • 析构函数:清理所有节点,防止内存泄漏。
  1. template<classT>classlist{typedef list_node<T> Node;public:typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T,const T&,const T*> const_iterator;list(){ _head =newNode(); _head->_next = _head; _head->_prev = _head; _size =0;}~list(){clear();delete _head;}
  2. iterator begin(){return _head->_next;}
  3. iterator end(){return _head;}voidpush_back(const T& x){insert(end(), x);}voidpush_front(const T& x){insert(begin(), x);}
  4. iterator insert(iterator pos,const T& x){
  5. Node* cur = pos._node;
  6. Node* prev = cur->_prev;
  7. Node* newnode =newNode(x);
  8. newnode->_next = cur; cur->_prev = newnode;
  9. prev->_next = newnode; newnode->_prev = prev;++_size;return newnode;}
  10. iterator erase(iterator pos){
  11. Node* cur = pos._node;
  12. Node* prev = cur->_prev;
  13. Node* next = cur->_next;
  14. prev->_next = next; next->_prev = prev;delete cur;--_size;return next;}voidclear(){
  15. iterator it =begin();while(it !=end()) it =erase(it);}
  16. size_t size()const{return _size;}boolempty()const{return _size ==0;}private:
  17. Node* _head;
  18. size_t _size;};

📌 5. 代码示例和测试

这些测试函数覆盖了自定义

  1. list

容器的基本功能,包括增删操作、迭代器遍历、插入与删除、拷贝构造、赋值运算等。在实际测试中,使用

  1. print_container

输出链表内容,便于观察操作结果。


🚀5.1

  1. test_list1()
  • 测试基本的增删操作与遍历
  1. voidtest_list1(){
  2. list<int> lt;
  3. lt.push_back(1);
  4. lt.push_back(2);
  5. lt.push_back(3);
  6. lt.push_back(4);
  7. lt.pop_back();// 删除最后一个元素
  8. lt.pop_front();// 删除第一个元素// 使用迭代器遍历链表,并将每个元素加10
  9. list<int>::iterator it = lt.begin();while(it != lt.end()){*it +=10;// 将每个元素的值加 10
  10. cout <<*it <<" ";++it;}
  11. cout << endl;// 使用自定义的print_container函数输出链表内容print_container(lt);}

解释

  • 初始化一个链表 lt 并插入元素。
  • 删除链表的尾部和头部元素。
  • 使用迭代器遍历链表,并对元素加 10 后输出。
  • print_container 函数打印链表的最终内容。

示例输出

  1. 12 13
  2. 12 13

🚀5.2

  1. test_list2()
  • 测试插入、修改与迭代器失效问题
  1. voidtest_list2(){
  2. list<int> lt;
  3. lt.push_back(1);
  4. lt.push_back(2);
  5. lt.push_back(3);
  6. lt.push_back(4);
  7. list<int>::iterator it = lt.begin();
  8. lt.insert(it,10);// 在开头插入10*it +=100;// 将第一个元素加100print_container(lt);// 遍历链表,删除所有偶数元素
  9. it = lt.begin();while(it != lt.end()){if(*it %2==0){
  10. it = lt.erase(it);// 删除偶数元素,并接收下一个有效迭代器}else{++it;}}print_container(lt);}

解释

  • 在链表开头插入 10,然后修改第一个元素的值。
  • 通过迭代器遍历链表,删除所有偶数元素。
  • 使用 erase 时注意接收返回的迭代器,以防迭代器失效。

示例输出

  1. 10 101 2 3 4
  2. 101 3

🚀5.3

  1. test_list3()
  • 测试拷贝构造和赋值操作
  1. voidtest_list3(){
  2. list<int> lt1;
  3. lt1.push_back(1);
  4. lt1.push_back(2);
  5. lt1.push_back(3);
  6. lt1.push_back(4);
  7. list<int>lt2(lt1);// 使用拷贝构造函数初始化lt2print_container(lt1);print_container(lt2);
  8. list<int> lt3;
  9. lt3.push_back(10);
  10. lt3.push_back(20);
  11. lt3.push_back(30);
  12. lt3.push_back(40);// 测试赋值操作
  13. lt1 = lt3;print_container(lt1);print_container(lt3);}

解释

  • 创建链表 lt1 并插入元素,使用 lt1 初始化链表 lt2(测试拷贝构造函数)。
  • 创建链表 lt3 并赋值给 lt1(测试赋值运算符的实现)。
  • 最后输出 lt1lt3 的内容,验证 lt1 是否成功拷贝了 lt3 的数据。

示例输出

  1. 1 2 3 4
  2. 1 2 3 4
  3. 10 20 30 40
  4. 10 20 30 40

📌 6. 性能分析与适用场景

  • 适用场景:自定义 list 容器适用于需要频繁插入和删除的场景,尤其是在链表头部和尾部操作较多时。
  • 性能分析:由于链表结构的特性,inserterase 操作在已知位置的时间复杂度为 O(1),但随机访问的效率低,适合顺序访问或遍历操作。

📌 7. 总结与扩展阅读

本文详细介绍了如何从零实现一个 C++ 双向链表

  1. list

容器,包括节点结构、迭代器设计、增删操作等。通过这篇文章的学习,希望你对

  1. list

的底层实现原理有了更深入的理解。推荐阅读以下文章进一步学习C++标准库和数据结构实现的相关知识:

  • C++数据结构与算法:链表详解
  • C++ 迭代器设计模式与实现技巧

📌 8. 互动与讨论

你在项目中使用过

  1. list

吗?你对本实现有其他的优化建议吗?欢迎在评论区讨论,分享你的想法和见解!


标签: c++ list 链表

本文转载自: https://blog.csdn.net/weixin_74837455/article/details/143649743
版权归原作者 起名字真南 所有, 如有侵权,请联系我们删除。

“【C++】从零实现 C++ 自定义 list 容器:双向链表与迭代器深度解析”的评论:

还没有评论