当前位置:   article > 正文

[C++]反向迭代器

反向迭代器

目录

前言:

1 对反向迭代器的构造思想

2 实现反向迭代器

3 完整代码


前言:

        本篇文章主要介绍了STL容器当中的反向迭代器,可能有朋友会说:“反向迭代器有什么好学的?不一样还是迭代器吗,我正向能写出来,还写不出反向?”有这种想法的朋友那你可得好好的看看咯,相信这对你有很大的帮助。

1 对反向迭代器的构造思想

        以同类逻辑去考虑迭代器,我们反向迭代器应该与正向迭代器构造思想相同,正向迭代器的begin指向第一个数据,end指向最后一个数据的后一位,那么我们的反向迭代器也应该是rbegin指向倒数第一个数据,rend指向第一个数据的前一位,如下图:

         我相信大多数人对于第一次遇到反向迭代器的想法都是这样的,包括博主自己,这也没有任何的问题,同样是能够实现反向迭代器的功能,但是这不是重点,我们实现这个思想时,多数会向下方代码那样,我以list举例,以这样的想法我们就会构建出这样的反向迭代器。

  1. template<class T, class Ref, class Ptr>
  2. struct __list_reverse_iterator
  3. {
  4. typedef list_node<T> node;
  5. typedef __list_reverse_iterator<T, Ref, Ptr> self;
  6. node* _node;
  7. __list_reverse_iterator(node* n)
  8. :_node(n)
  9. {}
  10. Ref operator*()
  11. {
  12. return _node->_data;
  13. }
  14. Ptr operator->()
  15. {
  16. return &_node->_data;
  17. }
  18. self& operator++()
  19. {
  20. _node = _node->_prev;
  21. return *this;
  22. }
  23. self operator++(int)
  24. {
  25. self tmp(*this);
  26. _node = _node->_prev;
  27. return tmp;
  28. }
  29. self& operator--()
  30. {
  31. _node = _node->_next;
  32. return *this;
  33. }
  34. self operator--(int)
  35. {
  36. self tmp(*this);
  37. _node = _node->_next;
  38. return tmp;
  39. }
  40. bool operator!=(const self& s)
  41. {
  42. return _node != s._node;
  43. }
  44. bool operator==(const self& s)
  45. {
  46. return _node == s._node;
  47. }
  48. };

        上述代码没有任何问题,博主也测试过能够实现反向迭代器的功能,但是呢看着这个代码是不是觉得很不爽啊,因为这反向迭代器通过这种另外封装一个类的方式,然后实现了一个与正向迭代器相互冗余的功能,这代码相似度太高了,写出来都觉得代码很挫,不好意思说出去是自己写的。

        基于此,请看看大佬是如何设计的吧。

         大佬干了啥,直接将正向迭代器作为反向迭代器的模板类型,在反向迭代器中重定义操作符,然后使用正向迭代器的功能,当然这个方式也是需要重新封装一个类,大伙还是看不出来有啥牛逼的,请继续往下看。

2 实现反向迭代器

代码:

  1. template<class iterator, class Ref, class Ptr>
  2. struct __list_reverse_iterator
  3. {
  4. typedef __list_reverse_iterator<iterator, Ref, Ptr> Self;
  5. iterator _cur;
  6. __list_reverse_iterator(iterator it)
  7. :_cur(it)
  8. {}
  9. Ref operator*()
  10. {
  11. iterator temp = _cur;
  12. return *(--temp);
  13. }
  14. Self& operator++()
  15. {
  16. --_cur;
  17. return *this;
  18. }
  19. Self& operator--()
  20. {
  21. ++_cur;
  22. return *this;
  23. }
  24. bool operator!=(const Self& ss)
  25. {
  26. return _cur != ss._cur;
  27. }
  28. };

        看到我们的代码,因为反向迭代器的类型是正向迭代器,所以我们需要在里面放置一个正向迭代器类型变量供使用。

        但是看到我们的反向迭代器构造了吗?我们对_cur变量赋初值等于iterator类型的it,但是it是怎么出来的?我们在使用反向迭代器的时候难道不是vv.rbegin();这种方式吗?我们有传递任何的数据吗?更何况还是一个正向迭代器类型的变量。

        此时就需要看到我们的rbegin函数了。

  1. reverse_iterator rbegin()
  2. {
  3. return reverse_iterator(end());
  4. }
  5. reverse_iterator rend()
  6. {
  7. return reverse_iterator(begin());
  8. }

        这样看可能不是很清楚,那我换一种方式表示:

reverse_iterator rbegin()
{
    return reverse_iterator(iterator(_head));
}

reverse_iterator rend()
{
    return reverse_iterator(iterator(_head->next));
}

        我们调用rbegin时,会实例化一个反向迭代器类,它通过正向迭代器去构造,正向迭代器通过结点指针构造。

        大家有注意到吗?这种实现方式的rbegin和rend指向我们数据的那个位置?和我们开头的思想相同吗?很明显不同,它的头指向了最后一个数据的下一个位置,它的尾指向了第一个位置,如下图。

         可是这样做的好处是什么?甚至我没有看到好处只看到了我之后*迭代器得到的数据都不对了,第一个数据都取不到了,但事实真的时是这样吗?回到代码中看:

Ref operator*()
{
     iterator temp = _cur;
     return *(--temp);
}

        我们在反向迭代器当中重定义*操作符函数下干了啥?我们创建了一个临时对象,将临时对象--在解引用,那么这样我们不就获取到了正确的数据了吗?所以这种构造思想没有错误。

        但是上面的道理大家都明白,好处在哪里?好了,重点到了!!

        看到上图,我们的begin对应的是rend,end对应的是rbegin,那么我们可以做一件什么事情呢?那就是反向迭代器类的参数传递可以通过正向迭代器的begin()、end()函数构建。也就是下方代码。

reverse_iterator rbegin()
{
    return reverse_iterator(end());
}
reverse_iterator rend()
{
    return reverse_iterator(begin());
}

         这也不是最重要的,最重要的是,我们将这份反向迭代器直接原封不动的放到vector当中,会有什么效果?你一定想不到,我们vector的反向迭代器也实现了!!

        如下:

  1. namespace boqi
  2. {
  3. template<class iterator, class Ref, class Ptr>
  4. struct __list_reverse_iterator
  5. {
  6. typedef __list_reverse_iterator<iterator, Ref, Ptr> Self;
  7. iterator _cur;
  8. __list_reverse_iterator(iterator it)
  9. :_cur(it)
  10. {}
  11. Ref operator*()
  12. {
  13. iterator temp = _cur;
  14. return *(--temp);
  15. }
  16. Self& operator++()
  17. {
  18. --_cur;
  19. return *this;
  20. }
  21. Self& operator--()
  22. {
  23. ++_cur;
  24. return *this;
  25. }
  26. bool operator!=(const Self& ss)
  27. {
  28. return _cur != ss._cur;
  29. }
  30. };
  31. template<class T>
  32. class vector
  33. {
  34. public:
  35. //迭代器定义
  36. typedef T* iterator;
  37. typedef const T* const_iterator;
  38. typedef struct __list_reverse_iterator<iterator, T&, T*> reverse_iterator;
  39. typedef struct __list_reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;
  40. iterator begin()
  41. {
  42. return _start;
  43. }
  44. iterator end()
  45. {
  46. return _finish;
  47. }
  48. reverse_iterator rbegin()
  49. {
  50. return reverse_iterator(end());
  51. }
  52. reverse_iterator rend()
  53. {
  54. return reverse_iterator(begin());
  55. }
  56. private:
  57. //三个迭代器表示一个开辟空间数组的3个位置
  58. iterator _start;
  59. iterator _finish;
  60. iterator _end_of_storage;
  61. };
  62. }

        看到,博主甚至连名字都没有更换,再看它是否能用。

测试代码:

  1. void test9()
  2. {
  3. yf::vector<int> vv;
  4. vv.push_back(1);
  5. vv.push_back(2);
  6. vv.push_back(3);
  7. vv.push_back(4);
  8. yf::vector<int>::reverse_iterator rit = vv.rbegin();
  9. while (rit != vv.rend())
  10. {
  11. cout << *rit << " ";
  12. ++rit;
  13. }
  14. cout << endl;
  15. }

输出:

         看到了吗?我们的vector的反向迭代器直接就能用了,我们都知道vector和list的底层完全不同,通过大佬的这种方式实现,却将两个完全不同的迭代器完美的联系起来了,并且共用一份代码!而且不只是这两个容器可以用,任何由迭代器的容器都可以使用,因为只要你有迭代器,那一定支持++和--,而且它不关心你的正向迭代器是怎么实现的。对此我只能膜拜,大佬不愧是大佬。

3 完整代码

  1. #pragma once
  2. #include<iostream>
  3. #include<list>
  4. #include<vector>
  5. #include<algorithm>
  6. #include<assert.h>
  7. namespace yf
  8. {
  9. template<class T>
  10. struct node
  11. {
  12. //结点类在list创建时分配数据
  13. node(const T& val = T())
  14. :next(nullptr)
  15. , prev(nullptr)
  16. , data(val)
  17. {}
  18. //前结点、后结点、T类型数据
  19. struct node<T>* next;
  20. struct node<T>* prev;
  21. T data;
  22. };
  23. //迭代器类
  24. //Ref和Ptr分别是T&,和T*,目的是为了不让代码冗余,const T&,const T*
  25. template<class T, class Ref, class Ptr>
  26. struct __list_iterator
  27. {
  28. typedef struct node<T> Node;
  29. typedef struct __list_iterator<T, Ref, Ptr> self;
  30. //浅拷贝传入过来的结点指针,不需要去开辟新空间
  31. //因为我们要的就是原本的结点
  32. struct __list_iterator(Node* node)
  33. :Pos(node)
  34. {}
  35. //*迭代器返回结点内部的数据
  36. Ref operator*()
  37. {
  38. return Pos->data;
  39. }
  40. //到下一个结点,而不是结点指针的下一个位置
  41. self& operator++()
  42. {
  43. Pos = Pos->next;
  44. return *this;
  45. }
  46. self operator++(int)
  47. {
  48. self temp = *this;
  49. Pos = Pos->next;
  50. return temp;
  51. }
  52. self& operator--()
  53. {
  54. Pos = Pos->prev;
  55. return *this;
  56. }
  57. self operator--(int)
  58. {
  59. self temp = *this;
  60. Pos = Pos->prev;
  61. return temp;
  62. }
  63. //返回节点数据的地址
  64. Ptr operator->()
  65. {
  66. //Pos已经是结点了,但是如果需要访问的数据也是一个结构体
  67. //那么获取到了它的地址,就能用->去访问了
  68. return &Pos->data;
  69. }
  70. bool operator==(const self& val)
  71. {
  72. return Pos == val.Pos;
  73. }
  74. bool operator!=(const self& val)
  75. {
  76. return Pos != val.Pos;
  77. }
  78. Node* Pos;
  79. };
  80. //反向迭代器
  81. template<class iterator, class Ref, class Ptr>
  82. struct __list_reverse_iterator
  83. {
  84. typedef __list_reverse_iterator<iterator, Ref, Ptr> Self;
  85. iterator _cur;
  86. __list_reverse_iterator(iterator it)
  87. :_cur(it)
  88. {}
  89. Ref operator*()
  90. {
  91. iterator temp = _cur;
  92. return *(--temp);
  93. }
  94. Self& operator++()
  95. {
  96. --_cur;
  97. return *this;
  98. }
  99. Self& operator--()
  100. {
  101. ++_cur;
  102. return *this;
  103. }
  104. bool operator!=(const Self& ss)
  105. {
  106. return _cur != ss._cur;
  107. }
  108. };
  109. //带头双向循环链表
  110. template<class T>
  111. class list
  112. {
  113. public:
  114. typedef struct node<T> Node;
  115. typedef struct __list_iterator<T, T&, T*> iterator;
  116. typedef struct __list_iterator<T,const T&, const T*> const_iterator;
  117. typedef struct __list_reverse_iterator<iterator, T&, T*> reverse_iterator;
  118. typedef struct __list_reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;
  119. iterator begin()
  120. {
  121. //进入迭代器类当中去,然后传入起始值的数据初始化
  122. return iterator(_head->next);
  123. }
  124. iterator end()
  125. {
  126. //_head相当于循环里的迭代器最后一个数据的下一个
  127. //所以初始化就用_head去初始化
  128. return iterator(_head);
  129. }
  130. const_iterator begin() const
  131. {
  132. return const_iterator(_head->next);
  133. }
  134. const_iterator end() const
  135. {
  136. return const_iterator(_head);
  137. }
  138. reverse_iterator rbegin()
  139. {
  140. return reverse_iterator(end());
  141. }
  142. reverse_iterator rend()
  143. {
  144. return reverse_iterator(begin());
  145. }
  146. const_reverse_iterator rbegin() const
  147. {
  148. return const_reverse_iterator(end());
  149. }
  150. const_reverse_iterator rend() const
  151. {
  152. return const_reverse_iterator(begin());
  153. }
  154. //构造时,有的对象是没有头结点的,所以需要帮忙开辟
  155. void Init_head()
  156. {
  157. _head = new Node;
  158. _head->next = _head;
  159. _head->prev = _head;
  160. }
  161. //无参
  162. list()
  163. {
  164. Init_head();
  165. }
  166. //拷贝
  167. list(const list<T>& val)
  168. {
  169. Init_head();
  170. list<T> temp(val.begin(), val.end());
  171. std::swap(_head, temp._head);
  172. }
  173. //赋值重载
  174. list<T>& operator=(list<T> val)
  175. {
  176. std::swap(_head, val._head);
  177. return *this;
  178. }
  179. //迭代器区间构造
  180. template<class InputIterator>
  181. list(InputIterator first, InputIterator last)
  182. {
  183. Init_head();
  184. while (first != last)
  185. {
  186. push_back(*first);
  187. ++first;
  188. }
  189. }
  190. //插入
  191. void insert(iterator pos, const T& val)
  192. {
  193. Node* cur = pos.Pos;
  194. Node* NewNode = new Node(val);
  195. cur->prev->next = NewNode;
  196. NewNode->prev = cur->prev;
  197. NewNode->next = cur;
  198. cur->prev = NewNode;
  199. }
  200. //尾插
  201. void push_back(const T& val)
  202. {
  203. iterator it = end();
  204. insert(it,val);
  205. }
  206. //头插
  207. void push_front(const T& val)
  208. {
  209. iterator it = begin();
  210. insert(it,val);
  211. }
  212. //删除
  213. void erase(iterator pos)
  214. {
  215. assert(pos != end());
  216. Node* cur = pos.Pos;
  217. cur->prev->next = cur->next;
  218. cur->next->prev = cur->prev;
  219. delete cur;
  220. }
  221. //尾删
  222. void pop_back()
  223. {
  224. iterator it = end();
  225. erase(--it);
  226. }
  227. //头删
  228. void pop_front()
  229. {
  230. iterator it = begin();
  231. erase(it);
  232. }
  233. //判空
  234. bool empty()
  235. {
  236. return _head->next == _head;
  237. }
  238. //清空除头结点之外的所有结点
  239. void clear()
  240. {
  241. iterator it = begin();
  242. while (it != end())
  243. {
  244. erase(it++);
  245. }
  246. }
  247. //析构
  248. ~list()
  249. {
  250. clear();
  251. delete _head;
  252. }
  253. private:
  254. Node* _head;
  255. };
  256. }

        以上就是我对反向迭代器的全部理解,谢谢大家观看。

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

闽ICP备14008679号