IT评测·应用市场-qidao123.com技术社区

标题: C++ STL:从零开始模仿实现 list 容器 [打印本页]

作者: 八卦阵    时间: 2025-4-22 04:01
标题: C++ STL:从零开始模仿实现 list 容器
引言

C++ 标准模板库(STL)中的 list 是一个双向链表容器,它提供了高效的插入和删除操作。本文将领导你一步步实现一个简化版的 list 容器,帮助你深入理解其底层原理和设计头脑。
1. 疑难点解析

1.1 迭代器类为什么设置三个模版参数?

   为了区分 listconst类平凡类 ,我们都知道 const类 的变量是不能修改内部值的,就算用指针也不行。而我们的迭代器也恰好是在模仿指针的举动,所以指针不能修改 const类 变量,我们的迭代器也不行。
为了区分对 const类list(只读)平凡类list(可读可写)的区别,我们需要另一个能做到对容器只读不写的 const类迭代器 ,我们最好的方式便是写两个基本一样的迭代器类(一份供平凡类list调用的平凡迭代器类,一份供const类list调用的const类的迭代器)。
但如许既欠好修改又欠好调试,而在有了模版之后,我们便可以将写两份代码的工作交给编译器去实现(俗称模版实例化,根据传入参数差别,模版可以实例化为多个差别类),所以我们就多加了一个模版参数Ref,根据 list 传入的范例差别,从而区分实例化为 const类 的迭代器照旧 平凡类 ,而又因为我们迭代器可以用 * 和 -> 两种操作符访问,且两操作符的返回值又各差别,所以 迭代器模版 又多加一个 Ptr ,以区分 ->运算符重载函数 对 const类平凡类 的访问。

  2. 完备源码

  1. #include<assert.h>
  2. namespace dza {
  3.         // 惯例:当成员变量和成员函数全部是公有的时候,一般用struct
  4.         // struct 与 class没有区别
  5.         template<class T>
  6.         struct list_node {
  7.                 T _data;
  8.                 list_node<T>* _next;
  9.                 list_node<T>* _prev;
  10.                 list_node(const T& x = T())
  11.                         :_data(x)
  12.                         , _next(nullptr)
  13.                         , _prev(nullptr)
  14.                 {}
  15.         };
  16.         // 单一参数的模板
  17.         //template<class T>
  18.         //struct list_iterator {
  19.         //        typedef list_node<T> Node;
  20.         //        // 定义一个迭代器Self
  21.         //        typedef list_iterator<T> Self;
  22.         //        Node* _node;
  23.         //        list_iterator(Node* node)
  24.         //                :_node(node)
  25.         //        {}
  26.         //        // 解引用的重载
  27.         //        T& operator*()
  28.         //        {
  29.         //                return _node->_data;
  30.         //        }
  31.         //        // 公共函数。域内都可以使用
  32.         //        T* operator->()
  33.         //        {
  34.         //                return &_node->_data;
  35.         //        }
  36.         //        // 迭代器的实现
  37.         //        Self& operator++()
  38.         //        {
  39.         //                _node = _node->_next;
  40.         //                return *this;
  41.         //        }
  42.         //        Self& operator--()
  43.         //        {
  44.         //                _node = _node->_prev;
  45.         //                return *this;
  46.         //        }
  47.         //        Self operator++(int)
  48.         //        {
  49.         //                Self tmp(*this);
  50.         //                _node = _node->_next;
  51.         //                return tmp;
  52.         //        }
  53.         //        Self operator--(int)
  54.         //        {
  55.         //                Self tmp(*this);
  56.         //                _node = _node->_prev;
  57.         //                return tmp;
  58.         //        }
  59.         //        bool operator!=(const Self& s)
  60.         //        {
  61.         //                return _node != s._node;
  62.         //        }
  63.         //        bool operator==(const Self& s)
  64.         //        {
  65.         //                return _node == s._node;
  66.         //        }
  67.         //};
  68.                 // 模板里面的多参数
  69.                 template<class T,class Ref,class Ptr>
  70.                 struct list_iterator {
  71.                         typedef list_node<T> Node;
  72.                         // 定义一个迭代器Self
  73.                         typedef list_iterator<T,Ref,Ptr> Self;
  74.                         Node* _node;
  75.                         list_iterator(Node* node)
  76.                                 :_node(node)
  77.                         {}
  78.                         // 解引用的重载
  79.                         Ref operator*()
  80.                         {
  81.                                 return _node->_data;
  82.                         }
  83.                         // 公共函数。域内都可以使用
  84.                         Ptr operator->()
  85.                         {
  86.                                 return &_node->_data;
  87.                         }
  88.                         // 迭代器的实现
  89.                         Self& operator++()
  90.                         {
  91.                                 _node = _node->_next;
  92.                                 return *this;
  93.                         }
  94.                         Self& operator--()
  95.                         {
  96.                                 _node = _node->_prev;
  97.                                 return *this;
  98.                         }
  99.                         Self operator++(int)
  100.                         {
  101.                                 Self tmp(*this);
  102.                                 _node = _node->_next;
  103.                                 return tmp;
  104.                         }
  105.                         Self operator--(int)
  106.                         {
  107.                                 Self tmp(*this);
  108.                                 _node = _node->_prev;
  109.                                 return tmp;
  110.                         }
  111.                         bool operator!=(const Self& s)
  112.                         {
  113.                                 return _node != s._node;
  114.                         }
  115.                         bool operator==(const Self& s)
  116.                         {
  117.                                 return _node == s._node;
  118.                         }
  119.                 };
  120.                 template<class T>
  121.                 class list {
  122.                         typedef list_node<T> Node;
  123.                 public:
  124.                         //typedef list_iterator<T> iterator;
  125.                         // typedef list_const_iterator<T> iterator;
  126.                         // 这个类要你自己实现
  127.                         // or
  128.                                                                                                           
  129.                     // list_iterator要有三个模板参数,才能用下面的迭代器,并且const是加在后面的,而不是前面
  130.                         typedef list_iterator<T, T&, T*> iterator;
  131.                         typedef list_iterator<T, const T&, const T*> const_iterator;
  132.                         iterator begin()
  133.                         {
  134.                                 return iterator(_head->_next);
  135.                         }
  136.                         iterator end()
  137.                         {
  138.                                 return iterator(_head);
  139.                         }
  140.                         const_iterator begin() const
  141.                         {
  142.                                 return const_iterator(_head->_next);
  143.                         }
  144.                         const_iterator end() const
  145.                         {
  146.                                 return const_iterator(_head);
  147.                         }
  148.                         void empty_init()
  149.                         {
  150.                                 _head = new Node();
  151.                                 _head->_next = _head;
  152.                                 _head->_prev = _head;
  153.                                 _size = 0;
  154.                         }
  155.                         list()
  156.                         {
  157.                                 empty_init();
  158.                         }
  159.                         // it2(it1) 的模拟实现
  160.                         list(const list<T>& It)
  161.                         {
  162.                                 empty_init();
  163.                                 for (auto& e : It)
  164.                                 {
  165.                                         push_back(e);
  166.                                 }
  167.                         }
  168.                         // it2 = it3 的模拟实现
  169.                         list<T>& operator=(list<T> It)
  170.                         {
  171.                                 swap(It);
  172.                                 return *this;
  173.                         }
  174.                         ~list()
  175.                         {
  176.                                 clear();
  177.                                 delete _head;
  178.                                 _head = nullptr;
  179.                         }
  180.                         void swap(list<T>& tmp)
  181.                         {
  182.                                 std::swap(_head, tmp._head);
  183.                                 std::swap(_size, tmp._size);
  184.                         }
  185.                         void clear()
  186.                         {
  187.                                 auto it = begin();
  188.                                 while (it != end())
  189.                                 {
  190.                                         it = erase(it);
  191.                                         // 删除链表中的所有节点
  192.                                         // erase在删除的时候会自动+1
  193.                                 }
  194.                         }
  195.                         // it1(3,1)的模拟实现。往list中插入3个1
  196.                         list(size_t n, const T& val = T())
  197.                         {
  198.                                 // 清空新链表
  199.                                 empty_init();
  200.                                 // 依次插入
  201.                                 for (size_t i = 0; i < n; i++)
  202.                                 {
  203.                                         push_back(val);
  204.                                 }
  205.                         }
  206.                         void push_back(const T& x)
  207.                         {
  208.                                 Node* new_node = new Node(x);// 指向待插入数据的指针
  209.                                 Node* tail = _head->_prev;// 头结点的上一个节点。也就是链表的最后一个节点
  210.                                 tail->_next = new_node;// 最后一个节点的 next 指向 new_node
  211.                                 new_node->_prev = tail;// new_node 的 prev 指向最后一个节点
  212.                                 new_node->_next = _head;// 由于 new_node 成为最后一个节点。所以更新链表中头结点的下一个指针
  213.                                 _head->_prev = new_node;// 头节点的 prev 指向 new_node
  214.                                 // // 新版本
  215.                                 // insert(end(),x);
  216.                         }
  217.                         void push_front(const T& x)
  218.                         {
  219.                                 insert(begin(), x);
  220.                         }
  221.                         void pop_front()
  222.                         {
  223.                                 erase(begin());
  224.                         }
  225.                         void pop_back()
  226.                         {
  227.                                 erase(--end());
  228.                         }
  229.                         iterator insert(iterator pos, const T& val)
  230.                         {
  231.                                 // cur 需要插入新数据的节点
  232.                                 Node* cur = pos._node;
  233.                                 // newnode 需要插入的新数据
  234.                                 Node* newnode = new Node(val);
  235.                                 // 需要插入新数据节点的上一个节点
  236.                                 Node* prev = cur->_prev;
  237.                                 // list是链表,所以想要头插,就只需要改变上一个节点的next,下一个节点的prev
  238.                                 prev->_next = newnode;// 上一个节点的 next 换成 newnode
  239.                                 newnode->_prev = prev;// 新数据指向上一个节点的指针 prev 指向上一个节点
  240.                                 newnode->_next = cur;// 新数据的下一个节点指向节点的原数据
  241.                                 cur->_prev = newnode;// 原节点的 prev 指向新数据
  242.                                 ++_size;// 改变整个链表的长度
  243.                                 // return iterator 通常表示一个函数返回一个 迭代器(iterator) 对象
  244.                                 // 它指向某个容器(如 std::vector、std::list、std::map 等)中的特定元素。
  245.                                 return iterator(newnode);// 返回新数据
  246.                         }
  247.                         iterator erase(iterator pos)
  248.                         {
  249.                                 // 先判断是不是空链表
  250.                                 assert(pos != end());
  251.                                 Node* del = pos._node;// 指向待删除数据的节点的指针
  252.                                 Node* next = del->_next;// 指向待删除数据节点的下一个节点
  253.                                 Node* prev = del->_prev;// 指向待删除数据节点的上一个节点
  254.                                 prev->_next = next;// 上一个节点的 next 指针指向下一个节点
  255.                                 next->_prev = prev;// 下一个节点的 prev 指针指向上一个节点
  256.                                 delete del;// 删除当前的节点
  257.                                 --_size;// 减小整个数组的size
  258.                                 // 返回待删除节点的下一个节点
  259.                                 return iterator(next);
  260.                         }
  261.                 private:
  262.                         Node* _head;
  263.                         size_t _size;
  264.                 };
  265.                 // 通用的 swap 模版。所有的类型都能用
  266.                 template <class T>
  267.                 void swap(T& a, T& b)
  268.                 {
  269.                         T c(a);
  270.                         a = b;
  271.                         b = c;
  272.                 }
  273.                 // 特化的 list_swap 版本。仅适用于 list<T>类型 使用
  274.                 // 特化的模版函数可以提高程序的运行效率
  275.                 template<class T>
  276.                 void swap(list<T>& a, list<T>& b)
  277.                 {
  278.                         a.swap(b);
  279.                 }
  280. }
复制代码
3. 完备测试代码

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include<iostream>
  3. using namespace std;
  4. #include<list>
  5. #include<vector>
  6. #include<algorithm>
  7. #include"list.h"
  8. //#include"teacher's list.h"
  9. class Pos
  10. {
  11. public:
  12.         int _row;
  13.         int _col;
  14.         Pos(int row = 0, int col = 0)
  15.                 :_row(row)
  16.                 , _col(col)
  17.         {
  18.                 cout << "Pos(int row, int col)" << endl;
  19.         }
  20.         Pos(const Pos& p)
  21.                 :_row(p._row)
  22.                 , _col(p._col)
  23.         {
  24.                 cout << "Pos(const Pos& p)" << endl;
  25.         }
  26. };
  27. void test_list01()
  28. {
  29.         dza::list<int> lt1;
  30.         lt1.push_back(1);
  31.         lt1.push_back(2);
  32.         lt1.push_back(3);
  33.         lt1.push_back(4);
  34.         for (auto& e : lt1)
  35.         {
  36.                 cout << e << " ";
  37.         }
  38.         cout << endl;
  39.         auto it1 = lt1.begin();
  40.         while (it1 != lt1.end())
  41.         {
  42.                 cout << *it1++ << " ";
  43.         }
  44.         cout << endl;
  45. }
  46. void test_list02()
  47. {
  48.         dza::list<int> lt1;
  49.     lt1.push_back(1);
  50.     lt1.push_back(1);
  51.         lt1.push_back(1);
  52.         lt1.push_back(1);
  53.         dza::list<int>::iterator it1 = lt1.begin();
  54.         while (it1 != lt1.end())
  55.         {
  56.                 *it1 = 2;
  57.                 cout << *it1 << " ";
  58.                 ++it1;
  59.         }
  60.         cout << endl;
  61.         for (auto e : lt1)
  62.         {
  63.                 cout << e << " ";
  64.         }
  65.         cout << endl;
  66. }
  67. void test_list03()
  68. {
  69.         dza::list<Pos> lt2;
  70.         // _row构造次数 == 0,_row构造次数 r1++
  71.         // _col构造次数 == 0,_col构造次数 c1++
  72.         Pos p1(1, 1);
  73.         lt2.push_back(p1);// r1++,c1++
  74.         lt2.push_back(Pos(2, 2)); // r1++,c1++
  75.         // {}隐式类型转换
  76.         lt2.push_back({ 3,3 });// r1++,c1++
  77.         // 动用4次_row构造。4次_col构造
  78.         dza::list<Pos>::iterator it2 = lt2.begin();
  79.         while (it2 != lt2.end())
  80.         {
  81.                 //cout << (*it2)._row << ":" << (*it2)._col << endl;
  82.                 // 为了可读性,特殊处理,省略了一个->
  83.                 // 两种读取方式。打印两次
  84.                 cout << it2->_row << ":" << it2->_col << endl;
  85.                 cout << it2.operator->()->_row << ":" << it2.operator->()->_col << endl;
  86.                 ++it2;
  87.         }
  88.         cout << endl;
  89. }
  90. void test_list04()
  91. {
  92.         dza::list<int> l1;
  93.         l1.push_back(1);
  94.         l1.push_back(2);
  95.         l1.push_back(3);
  96.         l1.push_back(4);
  97.         for (auto& e : l1)
  98.         {
  99.                 cout << e << " ";
  100.         }
  101.         cout << endl;
  102.         auto it1 = l1.begin();
  103.         int x = 0;
  104.         l1.pop_back();
  105.         while (it1 != l1.end())
  106.         {
  107.                 cout << *it1++ << " ";
  108.         }
  109.         cout << endl;
  110.        
  111.         // 头删完成之后需要更新一下it1。否则it1指向原来的位置,为空的迭代器
  112.         l1.pop_front();
  113.         it1 = l1.begin();
  114.         while (it1 != l1.end())
  115.         {
  116.                 cout << *it1++ << " ";
  117.         }
  118.         cout << endl;
  119.         l1.push_front(0);
  120.         l1.push_front(1);
  121.         for (auto& e : l1)
  122.         {
  123.                 cout << e << " ";
  124.         }
  125.         cout << endl;
  126. }
  127. void test_list05()
  128. {
  129.         dza::list<int> l1;
  130.         l1.push_back(1);
  131.         l1.push_back(2);
  132.         l1.push_back(3);
  133.         l1.push_back(4);
  134.         dza::list<int> l2(l1);
  135.         for (auto& e : l1)
  136.         {
  137.                 cout << e << " ";
  138.         }
  139.         cout << endl;
  140.         for (auto& e : l2)
  141.         {
  142.                 cout << e << " ";
  143.         }
  144.         cout << endl;
  145.         dza::list<int> l3(3,1);
  146.         for (auto& e : l3)
  147.         {
  148.                 cout << e << " ";
  149.         }
  150.         cout << endl;
  151.         l3.clear();
  152.         for (auto& e : l3)
  153.         {
  154.                 cout << e << " ";
  155.         }
  156.         cout << endl;
  157. }
  158. void test_list06()
  159. {
  160.         dza::list<int> l1;
  161.         l1.push_back(1);
  162.         l1.push_back(2);
  163.         l1.push_back(3);
  164.         l1.push_back(4);
  165.         for (auto& e : l1)
  166.         {
  167.                 cout << e << " ";
  168.         }
  169.         cout << endl;
  170.         auto it1 = l1.begin();
  171.         it1++;
  172.         it1++;
  173.         l1.insert(it1, 30);
  174.         for (auto& e : l1)
  175.         {
  176.                 cout << e << " ";
  177.         }
  178.         cout << endl;
  179.         l1.erase(l1.begin());
  180.         for (auto& e : l1)
  181.         {
  182.                 cout << e << " ";
  183.         }
  184.         cout << endl;
  185. }
  186. int main()
  187. {
  188.         test_list06();
  189.         return 0;
  190. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4