当前位置:   article > 正文

C++之List的模拟实现以及List反转迭代器的构建_c++ list反向遍历

c++ list反向遍历

一.List介绍

list的底层是双向循环链表,可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代,与其他底层是顺序表的容器(vector,array,deque)相比,list在任意位置进行插入,移除元素更加高效;但是和这些底层是顺序表的容器相比,list最大的缺陷就是不支持任意位置的随机访问。

二.成员变量

  1. public:
  2. Node* node;

list的成员变量只有一个节点类型的指针,它指向该双向循环链表的虚拟头节点。

二.list构造函数

  1. //无参构造函数
  2. list()
  3. {
  4. head = new Node();
  5. head->next = head;
  6. head->prev = head;
  7. }
  8. //利用模板函数以及迭代器来构造对象
  9. template<class Inputiterator>
  10. list(Inputiterator first, Inputiterator last)
  11. {
  12. head = new Node();
  13. head->next = head;
  14. head->prev = head;
  15. while (first != last)
  16. {
  17. push_back(*first);
  18. ++first;
  19. }
  20. }
  21. //深拷贝的拷贝构造函数,现代写法
  22. list(const list<T>& x)
  23. {
  24. head = new Node();
  25. head->next = head;
  26. head->prev = head;
  27. list<T> tmp(x.begin(), x.end());
  28. std::swap(head, tmp.head);
  29. }

注意:List的每一个构造函数都需要创建虚拟头节点 

 三.list iterator的使用:begin,end,rbegin,rend函数

3.1函数功能

 3.2代码实现

  1. //取头节点的迭代器
  2. iterator begin()
  3. {
  4. return iterator(head->next);
  5. }
  6. const_iterator begin() const
  7. {
  8. return const_iterator(head->next);
  9. }
  10. //以最后一个元素的下一个位置的迭代器构造的_revese_iterator作为返回值,就是用正向迭代器模拟实现反向迭代器,这是一种复用的表现,可以减少代码量
  11. _revese_iterator rbegin()
  12. {
  13. return _revese_iterator(end());
  14. }
  15. const_reverse_iterator rbegin() const
  16. {
  17. return const_reverse_iterator(end());
  18. }
  19. //取尾节点(虚拟头节点)的迭代器
  20. iterator end()
  21. {
  22. return iterator(head);
  23. }
  24. const_iterator end() const
  25. {
  26. return const_iterator(head);
  27. }
  28. //以第一个元素的迭代器构造的_revese_iterator作为返回值,就是用正向迭代器模拟实现反向迭代器,这是一种复用的表现,可以减少代码量
  29. _revese_iterator rend()
  30. {
  31. return _revese_iterator(begin());
  32. }
  33. const_reverse_iterator rend() const
  34. {
  35. return const_reverse_iterator(begin());
  36. }

 上面的_reverse_iterator反向迭代器是由正向迭代器构造实现的,这是一种设计模式,是一种复用的表现,可以减少代码量。

四.List类正向迭代器

4.1.list类迭代器的作用

利用List对象里的节点构造出迭代器,然后就可以使用该迭代器来遍历List对象中的每一个节点,实现解引用迭代器对象来完成取节点中的值的操作,还可以通过++,--来实现List对象中节点的遍历,list类迭代器本质上也是一个类,一个可以完成List对象中节点遍历的类。

4.2.成员变量

list的成员变量只有一个节点类型的指针,它指向该双向循环链表的虚拟头节点。

  1. public:
  2. Node* node;

 4.3.代码实现

  1. template<class T, class Ref, class Ptr>
  2. class __list_iterator
  3. {
  4. public:
  5. typedef ListNode<T> Node;
  6. typedef __list_iterator<T, Ref, Ptr> self;
  7. __list_iterator(Node* x)
  8. :node(x)
  9. {
  10. }
  11. //解引用运算符重载
  12. Ref operator*()
  13. {
  14. return node->data;
  15. }
  16. //-> 迭代器是借助节点的指针访问修改链表,这里表示用指针->->来获取数据,然后编译器会优化为指针->来获取数据
  17. Ptr operator->()
  18. {
  19. return &node->data;
  20. }
  21. //迭代器前置加加,返回加加后的迭代器
  22. self operator++()
  23. {
  24. node = node->next;
  25. return *this;
  26. }
  27. //迭代器后置加加,返回加加前的迭代器
  28. self operator++(int)
  29. {
  30. self tmp(node);
  31. node = node->next;
  32. return tmp;
  33. }
  34. //迭代器前置减减,返回减减后的迭代器
  35. self operator--()
  36. {
  37. node = node->prev;
  38. return *this;
  39. }
  40. //迭代器后置减减,返回减减前的迭代器
  41. self operator--(int)
  42. {
  43. self tmp(node);
  44. node = node->prev;
  45. return tmp;
  46. }
  47. //判断两个迭代器指向的内容是否相等
  48. bool operator!=(const self& it) const
  49. {
  50. if (it.node != node)
  51. {
  52. return true;
  53. }
  54. return false;
  55. }
  56. bool operator==(const self& it) const
  57. {
  58. return !(*this != it);
  59. }
  60. public:
  61. Node* node;
  62. };

 五.List类反向迭代器

5.1反向迭代器的介绍

它的作用是可以反向遍历List里面的每一个节点,它是由正向迭代器构造出来的,所以它所有功能都是由正向迭代器来实现的,与正向迭代器不同的是,当解引用反向迭代器的时候,取得不是当前迭代器指向的节点的值,而是取得是前一个节点的值,这是因为迭代器rend指向的是头节点,迭代器rbegin指向的是虚拟头节点。反向迭代器的--,和++操作,对应着正向迭代器的++,--操作。

5.2成员变量

  1. public:
  2. _iterator it;

是一个正向迭代器 

5.3代码实现:

  1. template<class iterator, class Ref, class Ptr>
  2. class resverse_iterator
  3. {
  4. public:
  5. typedef iterator _iterator;
  6. typedef resverse_iterator<iterator, Ref, Ptr> self;
  7. resverse_iterator(const _iterator& x)
  8. :it(x)
  9. {
  10. }
  11. //解引用运算符重载
  12. Ref operator*()
  13. {
  14. _iterator prev = it;
  15. return *(--prev);
  16. }
  17. //-> 迭代器是借助节点的指针访问修改链表,这里表示用指针->->来获取数据,然后编译器会优化为指针->来获取数据
  18. Ptr operator->()
  19. {
  20. _iterator prev = it;
  21. --prev;
  22. return &*(prev);
  23. }
  24. //迭代器前置加加,返回加加后的迭代器
  25. self operator++()
  26. {
  27. --it;
  28. return *this;
  29. }
  30. //迭代器后置加加,返回加加前的迭代器
  31. self operator++(int)
  32. {
  33. self tmp(it);
  34. --it;
  35. return tmp;
  36. }
  37. //迭代器前置减减,返回减减后的迭代器
  38. self operator--()
  39. {
  40. ++it;
  41. return *this;
  42. }
  43. //迭代器后置减减,返回减减前的迭代器
  44. self operator--(int)
  45. {
  46. self tmp(it);
  47. ++it;
  48. return tmp;
  49. }
  50. //判断两个迭代器指向的内容是否相等
  51. bool operator!=(const self& It) const
  52. {
  53. return it != It.it;
  54. }
  55. bool operator==(const self& It) const
  56. {
  57. return !(it != It.it);
  58. }
  59. public:
  60. _iterator it;
  61. };

六.push_back函数

6.1功能

在List链表中尾插一个节点

6.2返回值

无返回值

6.3实现逻辑

(1)先在堆上申请一块空间,这块空间存放着一个新节点的值

(2)让虚拟头节点的prev指针指向新节点,尾节点的next指针指向新节点

(3)新节点的prev指向尾节点,新节点的next指向虚拟头节点

  1. //尾插一个元素
  2. void push_back(const T& val)
  3. {
  4. Node* newnode = new Node(val);
  5. Node* _prev = head->prev;
  6. _prev->next = newnode;
  7. newnode->prev = _prev;
  8. newnode->next = head;
  9. head->prev = newnode;
  10. }

6.4实现结果 

七.erase函数

7.1功能

删除List对象中某个迭代器指向的节点,它可以是复用实现尾删,头删,以及清空List对象全部有效节点等功能

7.2返回值

返回下一个节点的迭代器

7.3实现逻辑

(1)要删除的节点的前一个节点指向要删除的节点的下一个节点

(2)释放要删除的节点的空间

  1. // 这里erase以后,pos是否失效?一定失效
  2. iterator erase(iterator pos)
  3. {
  4. assert(pos != end());
  5. Node* cur = pos.node;
  6. Node* pre = pos.node->prev;
  7. Node* _next = pos.node->next;
  8. pre->next = _next;
  9. _next->prev = pre;
  10. delete cur;
  11. iterator(_next);
  12. }
  13. //尾删一个元素
  14. void pop_back()
  15. {
  16. erase(--end());
  17. }
  18. //头删一个元素
  19. void pop_front()
  20. {
  21. erase(begin());
  22. }
  23. void clear()
  24. {
  25. //第一种方式:
  26. //list<int>::iterator it = begin();
  27. //while (it != end())
  28. //{
  29. // iterator del = it++;
  30. // delete del.node;
  31. //}
  32. //head->next = head;
  33. //head->prev = head;
  34. 另一种方式
  35. while (it != end())
  36. {
  37. erase(it++);
  38. }
  39. }

7.4实现结果 

八.insert函数

8.1功能

在迭代器pos指向的节点后面插入一个节点

8.2返回值

返回插入的新节点的迭代器

8.3实现逻辑

(1)先在堆上申请一块空间,这块空间存放着一个新节点的值

(2)让迭代器pos指向的节点的prev指针指向新节点,迭代器pos指向的节点的前一个节点的next指针指向新节点

(3)新节点的prev指向迭代器pos指向的节点的前一个节点,新节点的next指向迭代器pos指向的节点

  1. // 这里insert以后,pos是否失效?一定失效
  2. iterator insert(iterator pos, const T& x)
  3. {
  4. Node* newnode = new Node(x);
  5. Node* _prev = pos.node->prev;
  6. _prev->next = newnode;
  7. newnode->prev = _prev;
  8. newnode->next = pos.node;
  9. pos.node->prev = newnode;
  10. return iterator(newnode);
  11. }

8.4实现结果 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/390755?site
推荐阅读
相关标签
  

闽ICP备14008679号