• C++笔记 - - list的模拟实现和使用


    目录

    1.list的介绍和使用

    1.1 list的介绍

     1.2 list的使用

    1.2.1 list的构造

    1.2.2 list的迭代器使用

    1.2.3 list capacity

    1.2.4 list element access

    1.2.5 list modifiers

    1.2.6 list中的iterator迭代器失效问题

    2.list的模拟实现

    节点的类模板:

    list的类模板:

    迭代器的类模板


    1.list的介绍和使用

    1.1 list的介绍

    首先看一下文档当中是怎么说的

    list的文档介绍

     1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
    2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
    3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
    4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
    5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素) 



    1.2 list的使用

    1.2.1 list的构造

    默认构造
    explicit list (const allocator_type& alloc = allocator_type());
    构造n个val的list
    explicit list (size_type n, const value_type& val = value_type(),
                    const allocator_type& alloc = allocator_type());
    
    r迭代器区间构造
    template 
      list (InputIterator first, InputIterator last,
             const allocator_type& alloc = allocator_type());
    拷贝构造
    list (const list& x);

    1.2.2 list的迭代器使用

    begin()/end()返回第一个元素的迭代器+最后一个元素下一个位置的迭代器
    rbegin()/rend()返回第一个元素的reverse_iterato,即end(),返回最后一个元素下一个位置的reverse_iterator,即begin()

    注意:begin/end是正向迭代器,对迭代器执行++操作,迭代器向后移动

    rbegin/rend是反向迭代器,对迭代器执行++操作,迭代器向前移动

    1.2.3 list capacity

    empty判断链表是否为空,是返回true,不是返回false
    size返回链表有效节点个数

    1.2.4 list element access

    front返回第一个节点中值的引用
    back返回最后一个节点中值的引用

    1.2.5 list modifiers

    push_back尾插
    push_front头插
    pop_back尾删
    pop_front头删
    insert在迭代器pos位置插入
    erase在迭代器pos位置删除
    clear清空list中所有有效元素
    swap交换两个链表中的元素

    1.2.6 list中的iterator迭代器失效问题

    在list中,因为是一个个单独的节点构成,所以迭代器指向的是一个单独的节点。迭代器失效即迭代器指向的节点无效,节点被删除了。list底层是带头双向循环链表,进行插入迭代器不会失效,只有进行删除时才会失效,并且失效的只有指向被删除的节点的迭代器,其他迭代器不受到影响。


    2.list的模拟实现

    list的底层是使用带头双向循环链表实现的

    节点的类模板

    1. template<class T>
    2. struct list_node//这个类需要被外部访问,使用struct
    3. {
    4. typedef list_node Node;
    5. //成员变量
    6. T _val;
    7. list_node* _next;//类类型指针,指向自己的下一个节点
    8. list_node* _prev;
    9. //成员函数
    10. list_node(const T& val = T())//将参数val存入_val中
    11. :_val(val),
    12. _next(nullptr),
    13. _prev(nullptr)
    14. {
    15. }
    16. };

    成员变量:_val存储有效数据,_prev/_next分别指向前一个节点和后一个节点

    构造函数:将_val传入构造,无参的val就根据模板参数T创建匿名对象

    list的类模板:

    1. template<class T>
    2. class list
    3. {
    4. typedef list_node Node;
    5. public:
    6. typedef __list_iterator iterator;
    7. typedef __list_iteratorconst T&, const T*> const_iterator;
    8. void first_init()
    9. {
    10. _head = new Node;
    11. _head->_next = _head;
    12. _head->_prev = _head;
    13. }
    14. list()
    15. {
    16. first_init();
    17. }
    18. ~list()
    19. {
    20. clear();
    21. delete _head;
    22. _head = nullptr;
    23. }
    24. void clear()
    25. {
    26. iterator it = begin();
    27. while (it != end())
    28. {
    29. it = erase(it);
    30. }
    31. }
    32. void swap(list& tmp)
    33. {
    34. std::swap(_head, tmp._head);
    35. }
    36. bool empty()
    37. {
    38. return _head->_next == nullptr;
    39. }
    40. template <class InputIterator>
    41. list(InputIterator first, InputIterator last)
    42. {
    43. first_init();
    44. while (first != last)
    45. {
    46. push_back(first._node.val);
    47. first++;
    48. }
    49. }
    50. list(const list& lt)
    51. {
    52. first_init();
    53. list tmp(lt.begin(), lt.end());
    54. swap(tmp);
    55. }
    56. list& operator=(list lt)
    57. {
    58. swap(lt);
    59. return *this;
    60. }
    61. iterator begin()
    62. {
    63. return iterator(_head->_next);
    64. }
    65. iterator end()
    66. {
    67. return iterator(_head);
    68. }
    69. const_iterator begin()const
    70. {
    71. return const_iterator(_head->_next);
    72. }
    73. const_iterator end()const
    74. {
    75. return const_iterator(_head);
    76. }
    77. iterator insert(const iterator& pos, const T& val)
    78. {
    79. //申请节点
    80. Node* newnode = new Node(val);
    81. Node* front = pos._node->_prev;
    82. //进入链表
    83. newnode->_next = pos._node;
    84. newnode->_prev = front;
    85. front->_next = newnode;
    86. pos._node->_prev = newnode;
    87. return iterator(newnode);
    88. }
    89. void push_back(const T& val)
    90. {
    91. insert(end(), val);//尾差,传_head位置的迭代器
    92. }
    93. void push_front(const T& val)
    94. {
    95. insert(begin(), val);//头插,传第一个元素的迭代器
    96. }
    97. iterator erase(iterator pos)
    98. {
    99. assert(pos != end());
    100. //删除节点
    101. Node* front = pos._node->_prev;
    102. Node* back = pos._node->_next;
    103. delete pos._node;
    104. //链接链表
    105. front->_next = back;
    106. back->_prev = front;
    107. return iterator(back);
    108. }
    109. void pop_back()
    110. {
    111. erase(iterator(_head->_prev));//尾删,传最后一个位置的迭代器
    112. }
    113. void pop_front()
    114. {
    115. erase(begin());//头删,传第一个位置的迭代器
    116. }
    117. private:
    118. Node* _head;
    119. };

    迭代器的类模板

    1. template<class T, class Ref, class Ptr>//ref引用,ptr指针
    2. struct __list_iterator//迭代器需要被外部访问,使用struct
    3. {
    4. typedef __list_iterator iterator;
    5. typedef list_node Node;
    6. //成员变量
    7. Node* _node;
    8. __list_iterator(Node* node)//传节点的指针做形参,默认析构函数不对指针类型做处理
    9. :_node(node)
    10. {
    11. }
    12. bool operator!=(const iterator& it)//两个迭代器使用!=实际比较的是他们的指向是否指向同一节点
    13. {
    14. return _node != it._node;
    15. }
    16. bool operator==(const iterator& it)//加const可以匹配const_iterator类型,加引用表示对类的成员不可做修改
    17. {
    18. return _node == it._node;
    19. }
    20. iterator& operator++()//前置++返回++后的迭代器
    21. {
    22. _node = _node->_next;
    23. return *this;
    24. }
    25. iterator operator++(int)//后置++返回++前的迭代器 传值传参,因为tmp迭代器是临时对象,临时对象出了函数作用域会被销毁
    26. {
    27. iterator tmp(_node);
    28. _node = _node->_next;
    29. return tmp;
    30. }
    31. iterator& operator--()
    32. {
    33. _node = _node->_prev;
    34. return *this;
    35. }
    36. iterator operator--(int)
    37. {
    38. iterator tmp(_node);
    39. _node = _node->_prev;
    40. return tmp;
    41. }
    42. Ref operator*()//返回节点中_val的引用,因为val可能是一个自定义类型,传值返回会发生拷贝
    43. {
    44. return _node->_val;
    45. }
    46. Ptr operator->()
    47. {
    48. return &(operator*());
    49. }
    50. };

  • 相关阅读:
    SQL 基本操作
    Java日期时间类
    chatgpt赋能python:Python中的随机选择:介绍和应用
    聊一聊系统重构
    SpringMVC对消息转换器的处理相关
    ESD门禁闸机的使用说明
    6.S081-10 阻塞和唤醒+进程退出 - {Sleep & Week up}+{exit,wait,kill}
    pcie reset系列之 内核框架
    equals()方法
    物联网设备安装相关知识整理
  • 原文地址:https://blog.csdn.net/qq_64105689/article/details/127036940