• 【C++】STL——list模拟实现


    目录

    实现思路

    一、list的节点设计 

    二、list的初步框架 

    三、list的正向迭代器设计

    1.实现原理 

    2. 正向迭代器的结构

    四、list反向迭代器的设计

    1.实现原理

    2.反向迭代器的结构 

    1.反向迭代器的 ++ / -- 操作解析

    2.反向迭代器的 * / -> 操作解析

    五、list结构的完善 

    1.构造函数

    2.拷贝构造

    3.迭代器区间构造

    4.用n个val构造

    5.赋值重载

    6.析构函数

    7.迭代器的实现

    8.增删查改

    六、完整代码

    1.ListNode.h

    2.iterator.h

    3.reverse_iterator.h 

    4.list.h


    实现思路

            List是一个类模板,实际上是一个双向循环链表。在上一篇list基本使用的博客中,可以发现list支持了像vector一样的"下标访问",也就是通过迭代器区间去访问链表的每个节点数据。本人在初学阶段也是比较好奇——list的迭代器(正向与反向)是如何实现的;本篇博客将以自己所掌握的知识,详细的介绍list是如何实现的。

    list实现结构:

            1.节点设计

            2.正向迭代器设计

            3.反向迭代器设计

            4.list各个接口完善(增删查改)

    一、list的节点设计 

    list本身和list的结点是两个不同的结构,需要分开设计。以下是list的节点结构: 

    1. /*ListNode.h*/
    2. namespace mlg
    3. {
    4. template<class T>
    5. struct ListNode
    6. {
    7. ListNode<T>* _prev; //节点的前指针
    8. ListNode<T>* _next; //节点的后指针
    9. T _data; //节点的数据
    10. ListNode(const T& data= T())//初始化列表进行初始化
    11. :_prev(nullptr)
    12. ,_next(nullptr)
    13. ,_data(data)
    14. {}
    15. };
    16. }

            首先,我们在自己的命名空间内模拟实现list(为了防止与库冲突),上面的代码就是list节点的结构。在这里是用并没有使用class,因为struct默认访问权限是public,又因为节点是需要经常访问的,所以使用struct更好。

            我们将这个类加上 template<class T> 后,就能够实现节点存储不同类型的数据,这也是C++模板的好处。

    二、list的初步框架 

            当我们设计好了list的结点以后,我们就需要对list的基本框架进行设计,list要能够去控制这些节点,它的成员变量就必须是这个节点类;以下是list的结构设计:

    1. /*List.h*/
    2. namespace mlg //命名空间保持一致
    3. {
    4. template<class T> //list是一个类模板,设计时需要这个
    5. class list
    6. {
    7. typedef ListNode<T> Node; //将其类型重命名方便书写,在后续的类型中会有比较多的typedef
    8. public
    9. /*
    10. 成员函数包含了默认成员函数、迭代器和增删查改
    11. */
    12. private:
    13. Node* _head; //带头结点的双向循环链表
    14. };
    15. }

    在以上两个基本的框架搭建完毕以后,接下来重点主要是正向与反向迭代器

    三、list的正向迭代器设计

    1.实现原理 

            list的确是支持了迭代器,但是list不在能够像vector一样以普通的指针作为迭代器,因为其节点不保证在存储空间中连续。list的迭代器必须有能力指向list的节点,并有能力进行递增、递减、取值、成员存储等操作。如何具备这样的能力呢?那就是递增时指向下一个结点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取用的是节点的成员;

    2. 正向迭代器的结构

    1. /*iterator.h*/
    2. namespace mlg
    3. {
    4. template<class T,class Ref,class Ptr>
    5. struct __list_iterator
    6. {
    7. typedef ListNode<T> Node;
    8. typedef __list_iterator<T, Ref, Ptr> self;
    9. Node* _node;
    10. //迭代器构造函数
    11. __list_iterator(Node* x)
    12. :_node(x)
    13. {}
    14. //重载*号 —— 实现解引用操作
    15. Ref operator*()
    16. {
    17. return _node->_data;
    18. }
    19. //重载->操作符 —— 实现指针访问元素
    20. Ptr operator->()
    21. {
    22. return &_node->_data;
    23. }
    24. //++it 重载前置++ —— 让链表能够像数组一样去++操作,访问元素
    25. self& operator++()
    26. {
    27. _node = _node->_next;//前置++返回的是++之后的值,直接让当前位置的结点指向下一个节点
    28. return *this;
    29. }
    30. //it++ 重载后置++ —— (这里需要加上int作为一个站位符,与前置++区分)
    31. self operator++(int)
    32. {
    33. self tmp(*this);
    34. _node = _node->_next;//后置++返回的是++之前的值,需要保存当前节点,再指向下一个节点
    35. return tmp;
    36. }
    37. //--it 重载前置-- —— 让链表能够像数组一样去--操作,访问元素
    38. self& operator--()
    39. {
    40. _node = _node->_prev;//前置--返回的是--之后的值,直接让当前位置的结点指向前一个节点
    41. return *this;
    42. }
    43. //it-- 重载后置-- ——(这里需要加上int作为一个站位符,与前置--区分)
    44. self operator--(int)
    45. {
    46. self tmp(*this);
    47. _node = _node->_prev;//后置--返回的是--之前的值,需要保存当前节点,再指向下一个节点
    48. return tmp;
    49. }
    50. //重载==
    51. bool operator==(const self& it)const
    52. {
    53. return _node == it._node;
    54. }
    55. //重载!=
    56. bool operator!=(const self& it)const
    57. {
    58. return _node != it._node;
    59. }
    60. };
    61. }

    在上述代码中,有三个地方没有做解释:

    1. template<class T,class Ref,class Ptr>

    2. typedef __list_iterator<T, Ref, Refself;

            它是迭代器类模板,里面包含了三个参数:T、Ref、Ptr;这三个参数表明传给iterator类的类型是不确定的,需要根据实际的情况,将这三个参数匹配到相应的地方。

    如:

            1. ++/--操作:返回的是一个对象,只要用到了对象,一般都是写成__list_iterator<T, Ref, Ref>,因为类名太长,就有了第2点的typedef __list_iterator<T, Ref, Refself;

            2. operator* 操作:返回的是对象的数据的值,并且*号是具有读写操作的,我们应该返回的是这个数据类型的引用(T&);

            3. operator->操作:返回的是对象的数据的地址,我们应该返回的是这个数据类型的地址(T*);

    --------------------------------------------------------------------------------------------------------------------------

    3. typedef ListNode<T> Node;
        Node* _node;

            iterator类中的成员变量也是节点,我们刚刚已经解释了list迭代器的原理,它是通过重载++ / --,其内部实现上是节点中的_prev指针(找当前节点的前一个位置,相当于--操作)和_next指针(找当前节点的下一个位置,相当于++操作)的操作来实现的;

            所以,list正向迭代器的实现,本质上是用节点的两个指针的操作来代替了传统的++/--操作。再简单点说,其实就是函数调用(包括*/->

    四、list反向迭代器的设计

    1.实现原理

            我们刚刚对list正向迭代器做了介绍以后,你是否会想,反向迭代器也是同样的原理呢?确实可以这样理解,但是中间还有一个过程,我们先通下面的图解了解一下双链表(list)中和数组(vector)中正向迭代器与反向迭代器的区别。

    vector迭代器的位置不需要多说,对于list的迭代器:begin( )是数据的起始位置,end( )是数据的结束位置,也就是头结点;反向迭代器不就是与之相反嘛。

    那如何才能通过反向迭代器控制链表的++/--等一系列操作呢?

            方法一:我们可以重新写一个,也通过节点的指针去控制(比较麻烦:如果我想用正向迭代器区获取某个节点的位置传个反向迭代器,就需要给反向迭代器增设正向迭代器的接口)

            方法二:反向迭代器通过正向迭代器去间接控制list节点,达到想要的效果(在SLT原码中是这样子实现的,其目的是能适应其他容器,其称之为迭代器适配器

    2.反向迭代器的结构 

    1. /*reverse_iterator.h*/
    2. namespace mlg
    3. {
    4. template<class Iterator,class Ref,class Ptr>
    5. class __list_reverse_iterator
    6. {
    7. typedef __list_reverse_iterator<Iterator, Ref, Ptr> self;
    8. public:
    9. //反向迭代器构造函数(通过正向迭代器去构出造反向迭代器)
    10. __list_reverse_iterator(Iterator it)
    11. :_it(it)
    12. {}
    13. //重载*
    14. Ref operator*()
    15. {
    16. Iterator prev = _it; //获取正向迭代器end()的位置
    17. return *--prev; //返回的是当前位置执行前置--操作后的解引用
    18. }
    19. //重载->
    20. Ptr operator->()
    21. {
    22. return &operator*(); //调用上面一个重载函数
    23. }
    24. //++it
    25. self& operator++()
    26. {
    27. --_it; //反向迭代器的前置++就是调用正向迭代器的前置--
    28. return *this; //
    29. }
    30. //it++
    31. self operator++(int)
    32. {
    33. self tmp(*this); //后置++返回的是++之前的,所有先记录当前正向迭代器的位置
    34. _it--; //反向迭代器的后置++就是调用正向迭代器的后置--
    35. return tmp;
    36. }
    37. //--it
    38. self& operator--()
    39. {
    40. ++_it; //反向迭代器的前置--就是调用正向迭代器的前置++
    41. return *this;
    42. }
    43. //it--
    44. self operator--(int)
    45. {
    46. self tmp(*this); //后置--返回的是--之前的,所有先记录当前正向迭代器的位置
    47. _it++; //反向迭代器的后置--就是调用正向迭代器的后置++
    48. return tmp;
    49. }
    50. //重载!=
    51. bool operator!=(const self& rit)const
    52. {
    53. return _it != rit._it;
    54. }
    55. //重载==
    56. bool operator==(const self& rit)const
    57. {
    58. return _it == rit._it;
    59. }
    60. private:
    61. Iterator _it;//成员变量是一个正向迭代器
    62. };
    63. }

    1.反向迭代器的 ++ / -- 操作解析

    1. //++it
    2. self& operator++()
    3. {
    4. --_it; //调用正向迭代器的前置--
    5. return *this;
    6. }
    7. //it++
    8. self operator++(int)
    9. {
    10. self tmp(*this);
    11. _it--; //调用正向迭代器的后置--
    12. return tmp;
    13. }

      

    通过上图可以发现:

    1.反向迭代器++(前置/后置):调用正向迭代器的--

    2.反向迭代器--(前置/后置):调用正向迭代器的++

    2.反向迭代器的 * / -> 操作解析

    1. //重载*
    2. Ref operator*()
    3. {
    4. Iterator prev = _it; //获取正向迭代器end()的位置
    5. return *--prev; //返回的是当前位置执行前置--操作后的解引用
    6. }
    7. //重载->
    8. Ptr operator->()
    9. {
    10. return &operator*(); //调用上面一个重载函数
    11. }

    对于->的重载,只要去复用就可以了。 

    五、list结构的完善 

            上面我们对节点结构、正向与反向迭代器结构实现原理及注意点一一做了介绍,最后一步也是最重要的一步,那就是将list结构完善起来,实现list的功能。

    1.构造函数

            list的成员变量是一个节点类,在构造头节点时,需要将这单个头节点构造成一个双向循环链表;

     

    1. //构造函数
    2. list()
    3. {
    4. _head = new Node; //new一个节点出来
    5. _head->_prev = _head;
    6. _head->_next = _head; //_prev 和 _next 同时指向了头结点,形成了双向循链表
    7. }

    2.拷贝构造

            拷贝构造是用一个已有对象去构造出另一个对象,首先将待构造对象进行初始化,然后利用迭代器区间去构造一个和lt1一样的临时的tmp对象,再进行数据的交换,达到深拷贝的目的。 

    1. //拷贝构造 --- 现代写法 lt2(lt1)
    2. list(const list<T>& lt)
    3. {
    4. _head = new Node;
    5. _head->_prev = _head;
    6. _head->_next = _head;
    7. list<T> tmp(lt.begin(), lt.end());
    8. std::swap(_head, tmp._head);
    9. }

    3.迭代器区间构造

    通过传过来的迭代器区间进行初始化 

    1. //迭代器区间构造
    2. template<class IputIterator>
    3. list(IputIterator first, IputIterator last)
    4. {
    5. _head = new Node;
    6. _head->_prev = _head;
    7. _head->_next = _head;
    8. while (first != last)
    9. {
    10. push_back(*first);//尾插数据,会根据不同类型的迭代器进行调用
    11. ++first;
    12. }
    13. }

    4.用n个val构造

            通过用n个val来对对象进行初始化,需要注意这里的T( )是一个匿名对象,作为val的缺省参数,因为我们并不知道传给val的是一个对象还是一个整形(或其他),给缺省参数的好处在于,对于自定义类型编译器会去调用自定义类型的构造函数来对val进行初始化,如果是内置类型,它也是有自己的构造函数

    1. //我们常常对内置类型的定义是这样的
    2. int i = 10;
    3. //但其实也可以这样定义
    4. int i = int(10);
    1. //用n个val个构造
    2. list(int n, const T& val = T())
    3. {
    4. _head = new Node;
    5. _head->_prev = _head;
    6. _head->_next = _head;
    7. for (int i = 0; i < n; i++)
    8. {
    9. push_back(val);
    10. }
    11. }

    对于用n个val进行初始化和迭代器区间初始化,起初我是这样写的(为了和库一致) ,测试时却出现问题:非法的间接寻址

    1. //迭代器区间初始化
    2. template<class IputIterator>
    3. list(IputIterator first, IputIterator last){...}
    4. //用n个val初始化
    5. list(size_t n, const T& val = T()) {...}
    6. //测试日期类
    7. struct Date
    8. {
    9. int _year;
    10. int _month;
    11. int _day;
    12. Date(int year = 1, int month = 1, int day = 1)
    13. :_year(year)
    14. , _month(month)
    15. , _day(day)
    16. {}
    17. };
    18. void test_list4()
    19. {
    20. list<Date> lt1(5, Date(2022, 6, 21));//1
    21. for (auto e : lt1)
    22. {
    23. cout << e._year << "/" << e._month << "/" << e._day << endl;
    24. }
    25. cout << endl;
    26. list<int> lt2(5, 1);//2
    27. for (auto e : lt2)
    28. {
    29. cout << e << " ";
    30. }
    31. cout << endl;
    32. }

    5.赋值重载

    1. //赋值重载 --- 现代写法 lt2 = lt1
    2. list<T>& operator=(list<T> lt)
    3. {
    4. std::swap(_head, lt._head);
    5. return *this;
    6. }

    6.析构函数

    析构函数可以结合着erase函数看 

    1. ~list()
    2. {
    3. clear();
    4. delete _head;
    5. _head = nullptr;
    6. }
    7. void clear()
    8. {
    9. iterator it = begin();
    10. while (it != end())
    11. {
    12. //写法1
    13. erase(it++); //it是一个正向迭代器,采用后置++传给erase
    14. //写法2
    15. iterator del = it++;
    16. delete del._node;
    17. //写法3
    18. iterator del = it++;
    19. erase(del);
    20. }
    21. _head->_prev = _head;
    22. _head->_next = _head;
    23. }

    7.迭代器的实现

    在list类中,我们typedef了正向与反向迭代器,解释一下其目的及作用

    //正向迭代器    

    1. typedef __list_iterator<T, T&, T*> iterator;
    2. typedef __list_iterator<T, const T&, const T*> const_iterator;

    //反向迭代器

    1. typedef __list_reverse_iterator<iterator, T&, T*> reverse_iterator;
    2. typedef __list_reverse_iterator<iterator, const T&, const T*>const_reverse_iterator;

            list是一个类模板,参数列表是T类型(未知类型)正向与反向迭代器分别都有三个参数,在list内重命名相当于内嵌定义,显示传参,我们对迭代器中需要返回值的地方不能进行类型的准确判断,通过这种显示传参,确定了迭代器三个参数的基本对于类型。

            对于正向迭代器,我们显示传参<T、T&、T*>如果是const迭代器,再重新typedef一个const迭代器;

            对于反向迭代器,我们是需要正向迭代器去构造,所有显示传参就可以给到<iterator, T&, T*>

    1. namespace mlg
    2. {
    3. template<class T>
    4. class list
    5. {
    6. typedef ListNode<T> Node;
    7. public:
    8. //正向迭代器
    9. typedef __list_iterator<T, T&, T*> iterator;
    10. typedef __list_iterator<T, const T&, const T*> const_iterator;
    11. iterator begin()
    12. {
    13. return iterator(_head->_next);//返回头节点的下一个结点
    14. }
    15. iterator end()
    16. {
    17. return iterator(_head);//返回头节点
    18. }
    19. const_iterator begin()const
    20. {
    21. return const_iterator(_head->_next);//返回头节点的下一个结点
    22. }
    23. const_iterator end()const
    24. {
    25. return const_iterator(_head);//返回头节点
    26. }
    27. //反向迭代器
    28. typedef __list_reverse_iterator<iterator, T&, T*> reverse_iterator;
    29. typedef __list_reverse_iterator<iterator, const T&, const T*>const_reverse_iterator;
    30. reverse_iterator rbegin()
    31. {
    32. return reverse_iterator(end()); //返回正向迭代器的结束位置
    33. //return reverse_iterator(_head); //等价与正向迭代器的头节点
    34. }
    35. reverse_iterator rend()
    36. {
    37. return reverse_iterator(begin()); //返回正向迭代器的起始位置
    38. //return reverse_iterator(_head->_next); //等价于正向迭代器头节点的下一个结点
    39. }
    40. const_reverse_iterator rbegin()const
    41. {
    42. return const_reverse_iterator(end()); //返回正向迭代器的结束位置
    43. //return const_reverse_iterator(_head); //等价与正向迭代器的头节点
    44. }
    45. const_reverse_iterator rend()const
    46. {
    47. return const_reverse_iterator(begin()); //返回正向迭代器的起始位置
    48. //return const_reverse_iterator(_head->_next); //等价于正向迭代器头节点的下一个结点
    49. }
    50. };
    51. }

    8.增删查改

    1. //头插
    2. void push_front(const T& x)
    3. {
    4. insert(begin(), x);
    5. }
    6. //尾插
    7. void push_back(const T& x)
    8. {
    9. /*
    10. Node* tail = _head->_prev;
    11. Node* newnode = new Node(x);
    12. tail->_next = newnode;
    13. newnode->_prev = tail;
    14. newnode->_next = _head;
    15. _head->_prev = newnode;
    16. */
    17. insert(end(), x);
    18. }
    19. //头删
    20. void pop_front()
    21. {
    22. erase(begin());
    23. }
    24. //尾删
    25. void pop_back()
    26. {
    27. erase(--end());
    28. }
    29. //在pos位置插入元素x
    30. iterator insert(iterator pos, const T& x)
    31. {
    32. Node* cur = pos._node;
    33. Node* prev = cur->_prev;
    34. Node* newnode = new Node(x);
    35. prev->_next = newnode;
    36. newnode->_prev = prev;
    37. newnode->_next = cur;
    38. cur->_prev = newnode;
    39. return iterator(newnode);//在pos位置插入返回的是新插入的节点位置
    40. }
    41. //在pos位置删除元素
    42. iterator erase(iterator pos)
    43. {
    44. assert(pos != end());
    45. Node* prev = pos._node->_prev;
    46. Node* next = pos._node->_next;
    47. delete pos._node;
    48. prev->_next = next;
    49. next->_prev = prev;
    50. return iterator(next);//返回的是删除pos位置节点的下一个节点
    51. }

    六、完整代码

    1.ListNode.h

    1. #pragma once
    2. namespace mlg
    3. {
    4. template<class T>
    5. struct ListNode
    6. {
    7. ListNode<T>* _prev;
    8. ListNode<T>* _next;
    9. T _data;
    10. ListNode(const T& data= T())
    11. :_prev(nullptr)
    12. ,_next(nullptr)
    13. ,_data(data)
    14. {}
    15. };
    16. }

    2.iterator.h

    1. #pragma once
    2. namespace mlg
    3. {
    4. template<class T,class Ref,class Ptr>
    5. struct __list_iterator
    6. {
    7. typedef ListNode<T> Node;
    8. typedef __list_iterator<T, Ref, Ptr> self;
    9. typedef Ref reference;
    10. typedef Ptr pointer;
    11. Node* _node;
    12. __list_iterator(Node* x)
    13. :_node(x)
    14. {}
    15. Ref operator*()
    16. {
    17. return _node->_data;
    18. }
    19. Ptr operator->()
    20. {
    21. return &_node->_data;
    22. }
    23. //++it
    24. self& operator++()
    25. {
    26. _node = _node->_next;
    27. return *this;
    28. }
    29. //it++
    30. self operator++(int)
    31. {
    32. self tmp(*this);
    33. _node = _node->_next;
    34. return tmp;
    35. }
    36. //--it
    37. self& operator--()
    38. {
    39. _node = _node->_prev;
    40. return *this;
    41. }
    42. //it--
    43. self operator--(int)
    44. {
    45. self tmp(*this);
    46. _node = _node->_prev;
    47. return tmp;
    48. }
    49. bool operator==(const self& it)const
    50. {
    51. return _node == it._node;
    52. }
    53. bool operator!=(const self& it)const
    54. {
    55. return _node != it._node;
    56. }
    57. };
    58. }

    3.reverse_iterator.h 

    1. #pragma once
    2. namespace mlg
    3. {
    4. template<class Iterator,class Ref,class Ptr>
    5. class __list_reverse_iterator
    6. {
    7. typedef __list_reverse_iterator<Iterator, Ref, Ptr> self;
    8. public:
    9. __list_reverse_iterator(Iterator it)
    10. :_it(it)
    11. {}
    12. Ref operator*()
    13. {
    14. Iterator prev = _it;
    15. return *--prev;
    16. }
    17. Ptr operator->() {return &operator*();}
    18. //++it
    19. self& operator++()
    20. {
    21. --_it;
    22. return *this;
    23. }
    24. //it++
    25. self operator++(int)
    26. {
    27. self tmp(*this);
    28. _it--;
    29. return tmp;
    30. }
    31. //--it
    32. self& operator--()
    33. {
    34. ++_it;
    35. return *this;
    36. }
    37. //it--
    38. self operator--(int)
    39. {
    40. self tmp(*this);
    41. _it++;
    42. return tmp;
    43. }
    44. bool operator!=(const self& rit)const {return _it != rit._it;}
    45. bool operator==(const self& rit)const {return _it == rit._it;}
    46. private:
    47. Iterator _it;
    48. };
    49. }

    4.list.h

    1. #pragma once
    2. #include "ListNode.h"
    3. #include "iterator.h"
    4. #include "reverse_iterator.h"
    5. namespace mlg
    6. {
    7. template<class T>
    8. class list
    9. {
    10. typedef ListNode<T> Node;
    11. public:
    12. //正向迭代器
    13. typedef __list_iterator<T, T&, T*> iterator;
    14. typedef __list_iterator<T, const T&, const T*> const_iterator;
    15. iterator begin() {return iterator(_head->_next);}
    16. iterator end() {return iterator(_head);}
    17. const_iterator begin()const {return const_iterator(_head->_next);}
    18. const_iterator end()const {return const_iterator(_head);}
    19. //反向迭代器
    20. typedef __list_reverse_iterator<iterator, T&, T*> reverse_iterator;
    21. typedef __list_reverse_iterator<iterator, const T&, const T*> const_reverse_iterator;
    22. reverse_iterator rbegin() {return reverse_iterator(end());}
    23. reverse_iterator rend() {return reverse_iterator(begin());}
    24. const_reverse_iterator rbegin()const {return const_reverse_iterator(end());}
    25. const_reverse_iterator rend()const {return const_reverse_iterator(begin());}
    26. //构造函数
    27. list()
    28. {
    29. _head = new Node; //new一个节点出来
    30. _head->_prev = _head;
    31. _head->_next = _head; //_prev 和 _next 同时指向了头结点,形成了双向循链表
    32. }
    33. //用n个val个构造
    34. list(int n, const T& val = T())
    35. {
    36. _head = new Node;
    37. _head->_prev = _head;
    38. _head->_next = _head;
    39. for (int i = 0; i < n; i++)
    40. {
    41. push_back(val);
    42. }
    43. }
    44. //迭代器区间构造
    45. template<class IputIterator>
    46. list(IputIterator first, IputIterator last)
    47. {
    48. _head = new Node;
    49. _head->_prev = _head;
    50. _head->_next = _head;
    51. while (first != last)
    52. {
    53. push_back(*first);
    54. ++first;
    55. }
    56. }
    57. //拷贝构造 --- 现代写法 lt2(lt1)
    58. list(const list<T>& lt)
    59. {
    60. _head = new Node;
    61. _head->_prev = _head;
    62. _head->_next = _head;
    63. list<T> tmp(lt.begin(), lt.end());
    64. std::swap(_head, tmp._head);
    65. }
    66. //赋值重载 --- 现代写法 lt2 = lt1
    67. list<T>& operator=(list<T> lt)
    68. {
    69. std::swap(_head, lt._head);
    70. return *this;
    71. }
    72. ~list()
    73. {
    74. clear();
    75. delete _head;
    76. _head = nullptr;
    77. }
    78. void clear()
    79. {
    80. iterator it = begin();
    81. while (it != end())
    82. {
    83. erase(it++);
    84. }
    85. _head->_prev = _head;
    86. _head->_next = _head;
    87. }
    88. void push_front(const T& x){ insert(begin(), x); }
    89. void push_back(const T& x) { insert(end(), x);}
    90. void pop_front() {erase(begin());}
    91. void pop_back(){erase(--end());}
    92. //在pos位置插入元素x
    93. iterator insert(iterator pos, const T& x)
    94. {
    95. Node* cur = pos._node;
    96. Node* prev = cur->_prev;
    97. Node* newnode = new Node(x);
    98. prev->_next = newnode;
    99. newnode->_prev = prev;
    100. newnode->_next = cur;
    101. cur->_prev = newnode;
    102. return iterator(newnode);
    103. }
    104. //在pos位置删除元素
    105. iterator erase(iterator pos)
    106. {
    107. assert(pos != end());
    108. Node* prev = pos._node->_prev;
    109. Node* next = pos._node->_next;
    110. delete pos._node;
    111. prev->_next = next;
    112. next->_prev = prev;
    113. return iterator(next);
    114. }
    115. private:
    116. Node* _head;
    117. };
    118. void print_list(const list<int>& lt)
    119. {
    120. list<int>::const_iterator it = lt.begin();
    121. while (it != lt.end())
    122. {
    123. cout << *it << " ";
    124. ++it;
    125. }
    126. cout << endl;
    127. }
    128. void test_list5()
    129. {
    130. list<int> lt;
    131. lt.push_back(1);
    132. lt.push_back(2);
    133. lt.push_back(3);
    134. lt.push_back(4);
    135. list<int>::reverse_iterator rit = lt.rbegin();
    136. while (rit != lt.rend())
    137. {
    138. cout << *rit << " ";
    139. ++rit;
    140. }
    141. cout << endl;
    142. }
    143. }

             以上是对list模拟实现的全部结束,大家可以在.c文件下进行测试。如果存在任何问题,或者有不同的见解,大家可以直接在评论区提出来

  • 相关阅读:
    iis站点https绑定
    Docker实战:Docker安装nginx并配置SSL
    e^x的导数
    BiSeNet v2
    java 项目管理工具gradle
    网络流量监控与DNS流量分析
    Python3:@property属性装饰器
    MegEngine Inference 卷积优化之 Im2col 和 winograd 优化
    微信小程序之后台首页交互
    基于Java的医院预约挂号系统设计与实现(源码+lw+部署文档+讲解等)
  • 原文地址:https://blog.csdn.net/sjsjnsjnn/article/details/125451866