• 【C++】反向迭代器--迭代器适配器


    前言

            大家好呀~欢迎进入我的这篇学习笔记~ 我的上一篇C++文章传送点在这里哦:【C++】stack、queue、priority_queue的模拟实现_柒海啦的博客-CSDN博客

            我们知道,在C++的STL容器中,有着一个重要的迭代器,也就是和正向迭代器不一样的反向迭代器。这篇学习笔记,将带大家认清理清楚反向迭代器如何通过正向迭代器进行复用实现,达到一个多种容器都能使用的结果。

            废话不多说,我们直接开始吧:

    目录

    1.引入

    2.代码实现

    3.综合代码

    4.测试vector和list


    1.引入

            在前面,相信大家也见识过了容器适配器。实际上就是在复用STL的其他容器的时候,搞得一个模板参数进行替代,能够做到用不同的容器进行底层实现。只要底层所调用的方法一致就不会出现问题,但是效率问题就要看用户本身是如何去想的了。

            实际上,反向迭代器的实现也就是迭代器适配器的实现。我们只需要控制传入一个正向迭代器,根据此正向迭代器的相同调用完成反向迭代器,已达到不同的容器均可以使用此反向迭代器类模板,只要实现了正向迭代器的类似功能。

             比如我们写一个反向迭代器,让list和vector都能够使用此反向迭代器。(list的正向迭代器封装过,vector的正向迭代器是原生指针)

            要执行反向迭代器,实际上也就是完成和正向迭代器相反的功能(也可以直接写一个反向迭代器,直接使用容器底层的结构,但是这样并没有复用,并且也打不到适配器的效果),正向迭代器++对应反向的--,--对应反向的++,其余类似。

            如上图所示,每个容器对自己的数据进行一个封装成正向迭代器,使其能像指针那样去访问数据。而反向迭代器无需关系容器内部数据结构,只需要正向迭代器提供相应的功能我来进行封装即可。

    2.代码实现

            首先,此反向迭代器自然是模板类,首先是类似于正向迭代器封装实现模板的那一套,T&和T*分开传入。只不过此时数据不再是类型T,而是iterator:

    1. // iterator T& T*
    2. template<class Iterator, class Ref, class Ptr>

            定义成struct方便全部设置为public,方便访问,类名和库一致:__reverse_iterator。成员自然就是我们的正向迭代器,把自身调用重命名一下(后面有些接口需要传出自己)

    1. // iterator T& T*
    2. template<class Iterator, class Ref, class Ptr>
    3. struct __reverse_iterator
    4. {
    5. Iterator _cur;
    6. typedef __reverse_iterator reverse_iterator;
    7. ......
    8. }

            构造函数需要传入一个正向迭代器,初始化给我们的成员变量:

    1. __reverse_iterator(Iterator it)
    2. :_cur(it)
    3. {}

            ++和--分别调用正向迭代器的--和++即可:

    1. reverse_iterator& operator++()
    2. {
    3. --_cur;
    4. return *this;
    5. }
    6. reverse_iterator operator++(int)
    7. {
    8. reverse_iterator tmp(_cur);
    9. --_cur;
    10. return tmp;
    11. }
    12. reverse_iterator& operator--()
    13. {
    14. ++_cur;
    15. return *this;
    16. }
    17. reverse_iterator operator--(int)
    18. {
    19. reverse_iterator tmp(_cur);
    20. ++_cur;
    21. return tmp;
    22. }

            解引用需要注意,因为此时第一个传入的应该是end(rbegin),即反向迭代器是从正向迭代器的end开始遍历,而end是指向数据最后一个的下一个位置,所以我们要在不改变此时所在位置的情况下,访问前一个位置的数据即可:

    1. Ref operator*()
    2. {
    3. Iterator tmp = _cur;
    4. --tmp;
    5. return *tmp;
    6. }

            ->表示指针访问某个成员所用符号,所以我们应该返回指针即地址,所以就复用上面的取值,然后取地址即可:

    1. Ptr operator->()
    2. {
    3. return (&operator*());
    4. }

            != 和 == 直接复用正向迭代器的即可:

    1. bool operator!=(const reverse_iterator& r)
    2. {
    3. return _cur != r._cur;
    4. }
    5. bool operator==(const reverse_iterator& r)
    6. {
    7. return _cur == r._cur;
    8. }

    3.综合代码

    1. #pragma once
    2. // 实现反向迭代器配置 利用原本的迭代器作为容器
    3. namespace YuShen
    4. {
    5. // iterator T& T*
    6. template<class Iterator, class Ref, class Ptr>
    7. struct __reverse_iterator
    8. {
    9. Iterator _cur;
    10. typedef __reverse_iterator reverse_iterator;
    11. __reverse_iterator(Iterator it)
    12. :_cur(it)
    13. {}
    14. reverse_iterator& operator++()
    15. {
    16. --_cur;
    17. return *this;
    18. }
    19. reverse_iterator operator++(int)
    20. {
    21. reverse_iterator tmp(_cur);
    22. --_cur;
    23. return tmp;
    24. }
    25. reverse_iterator& operator--()
    26. {
    27. ++_cur;
    28. return *this;
    29. }
    30. reverse_iterator operator--(int)
    31. {
    32. reverse_iterator tmp(_cur);
    33. ++_cur;
    34. return tmp;
    35. }
    36. Ref operator*()
    37. {
    38. Iterator tmp = _cur;
    39. --tmp;
    40. return *tmp;
    41. }
    42. Ptr operator->()
    43. {
    44. return (&operator*());
    45. }
    46. bool operator!=(const reverse_iterator& r)
    47. {
    48. return _cur != r._cur;
    49. }
    50. bool operator==(const reverse_iterator& r)
    51. {
    52. return _cur == r._cur;
    53. }
    54. };
    55. }

    4.测试vector和list

            分别在list和vector导入后,进行测试:

     

             vector的具体模拟实现链接在这里哦~:【C++】vector从理解到深入_柒海啦的博客-CSDN博客

            测试代码:

     

     

             可以发现,测试的非常成功。明明两个正向迭代器的底层实现都不相同(一个封装实现,一个原生指针)。其实我们发现反向迭代器的实现利用的都是接口罢了。所以,只要正向迭代器提供相同的接口(++ -- 随机访问等等.....),就能统一的进行实现,此反向迭代器也就有了它作为模板类的意义。

  • 相关阅读:
    maven本地仓库存在jar导包时依然试图远程仓库下载问题解决
    Vue01-vue的简介
    【Redis7】--2.十大数据类型
    Web端阿里云音视频通信推流、拉流demo
    # LeetCode第169题—多元数组
    【接口测试】接口测试内容
    canal 与 dbz ddl与dml数据结构
    leetcode 习题集 【9月】
    【VMware/Linux】虚拟机根目录扩容
    C/C++教程 从入门到精通《第十五章》—— MFC资源详解
  • 原文地址:https://blog.csdn.net/weixin_61508423/article/details/127099923