反向迭代器

反向迭代器的定义

反向迭代器是一种迭代器适配器,它重新定义了递增和递减操作,使其行为在逻辑上与原始迭代器相反。
当我们对反向迭代器进行递增时,它实际上会向容器起始方向移动(即递减内部的基础迭代器);而递减则向容器末尾方向移动(递增内部的基础迭代器)。

在这里插入图片描述

如何获取反向迭代器

C++容器(如vector, list, deque等)提供了rbegin()和rend()成员函数,用于获取反向迭代器。

  • rbegin(): 返回一个指向容器最后一个元素的反向迭代器。
  • rend(): 返回一个指向容器第一个元素前一个位置的反向迭代器。

同样,还有crbegin()和crend(),它们返回常量反向迭代器。

反向迭代器的操作

反向迭代器支持与普通迭代器相似的操作,如解引用、递增、递减等。但是要注意:

解引用反向迭代器时,返回的是其内部基础迭代器前一个位置的元素的引用。这是因为反向迭代器的设计是为了提供与正向迭代器对称的行为。
具体来说,rbegin()指向最后一个元素,而rend()指向第一个元素之前,这样当使用反向迭代器遍历时,从rbegin()到rend()就相当于从最后一个元素到第一个元素。

反向迭代器与普通迭代器的关系

适配器模式

反向迭代器内部包装了一个普通迭代器(基础迭代器),并通过调整递增和递减的含义来实现反向遍历。使用了适配是的设计模式,让设计更加容易,复用率高。除此之外,const迭代器也可以适配出const反向迭代器,大大提升开发效率。

注意事项:

我们在封装代码的时候,rend应返回begin(),rbegin()应返回rend()。那么在使用反向迭代器遍历的时候,解引用操作在rbegin()的时候就会解引用到end(),这样就会产生非法操作,因此我们可以在解引用的时候解引用end()–的位置,这样就可以完美避开缺陷,同时又使得迭代器与反向迭代器呈现对称关系。

在这里插入图片描述

封装代码

#pragma once
#include<iostream>

namespace ReIterator{

    template <class Iterator , class Ref, class Ptr>
    class reverse_iterator{

        typedef reverse_iterator<Iterator, Ref, Ptr> Self;
        Iterator _reit;
        public:
            reverse_iterator(const Iterator& it = Iterator()):_reit(it)
        { }
        Self& operator++()
        {
            return --_reit;
        }

        Self operator++(int)
        {
            return _reit--;
        }

        Self& operator--()
        {
            return ++_reit;
        }

        Self operator--(int)
        {
            return _reit++;
        }

        Ref operator*() 
        {
            Iterator tmp = _reit;
            return *(--tmp);
        }

        Ptr operator->() 
        {
            Iterator tmp = _reit;
            tmp--;
            return tmp.operator->();
        }

        bool operator==(const Self& it) const
        {
            return _reit == it._reit;
        }
        bool operator!=(const Self& it) const
        {
            return _reit != it._reit;
        }

    };
}

namespace mylist
{
    template <class T>
    struct ListNode
    {
        T _val = 0;
        ListNode *_next = nullptr;
        ListNode *_prev = nullptr;
        ListNode(const T &val = T()) : _val(val)
        {
        }
    };

    template <class T>
    class list;

    template <class T, class Ref, class Ptr>
    class ListIterator
    {
        typedef ListNode<T> Node;
        typedef ListIterator<T, Ref, Ptr> self;

        Node *_node;
        friend class list<T>;

    public:
        ListIterator(Node *node = nullptr) : _node(node)
        {
        }

        Ref operator*()
        {
            return _node->_val;
        }
        Ptr operator->()
        {
            return &(_node->_val);
        }
        self &operator++()
        {
            _node = _node->_next;
            return *this;
        }

        self operator++(int)
        {
            self &tmp = *this;
            _node = _node->_next;
            return tmp;
        }
        self operator--()
        {
            _node = _node->_prev;
            return *this;
        }

        self &operator--(int)
        {
            self &tmp = *this;
            _node = _node->_prev;
            return tmp;
        }

        bool operator==(const self &it) const
        {
            return it._node == _node;
        }

        bool operator!=(const self &it) const
        {
            return it._node != _node;
        }
    };

   
    template <class T>
    class list
    {

        typedef ListNode<T> Node;
        Node *_head = nullptr;
        size_t _size = 0;

    public:
        typedef ListIterator<T, T &, T *> iterator;
        typedef ListIterator<T, const T &, const T *> const_iterator;
        typedef ReIterator::reverse_iterator < iterator, T&, T*> reverse_iterator;
        typedef ReIterator::reverse_iterator < const_iterator, const T&, const T*> const_reverse_iterator;


        list()
        {
            Init();
        }

        list(size_t n, const T &val = T())
        {
            Init();
            while (n--)
            {
                push_back(val);
            }
        }
        list(iterator first, iterator last)
        {
            Init();
            while (first != last)
            {
                push_back(*first);
                first++;
            }
        }

        list(const list<T> &lt)
        {
            Init();
            const_iterator it = lt.cbegin();
            while (it != lt.cend())
            {
                push_back(*it);
                it++;
            }
        }

        void Init()
        {
            _head = new Node;
            _head->_next = _head;
            _head->_prev = _head;
        }

        iterator begin()
        {
            return _head->_next;
        }
        iterator end()
        {
            return _head;
        }

        const_iterator cbegin() const
        {
            return _head->_next;
        }
        const_iterator cend() const
        {
            return _head;
        }

        reverse_iterator rbegin()
        {
            return end();
        }

        reverse_iterator rend()
        {
            return begin();
        }

        const_reverse_iterator crbegin() const
        {
            return cend();
        }

        const_reverse_iterator crend() const
        {
            return cbegin();
        }

        const_reverse_iterator rbegin() const
        {
            return cend();
        }

        const_reverse_iterator rend() const
        {
            return cbegin();
        }

        iterator insert(iterator pos, const T &val)
        {
            Node *newnode = new Node(val);
            Node *next = pos._node;
            Node *prev = next->_prev;

            prev->_next = newnode;
            newnode->_prev = prev;
            newnode->_next = next;
            next->_prev = newnode;

            _size++;
            return newnode;
        }

        iterator erase(iterator pos)
        {
            assert(!empty());
            Node *next = pos._node->_next;
            Node *prev = pos._node->_prev;

            prev->_next = next;
            next->_prev = prev;
            delete pos._node;
            _size--;
            return next;
        }
        void push_back(const T &val)
        {
            // Node *newnode = new Node(val);

            // if (newnode != nullptr)
            // {
            //     _head->_prev->_next = newnode;
            //     newnode->_prev = _head->_prev;

            //     _head->_prev = newnode;
            //     newnode->_next = _head;
            // }

            insert(end(), val);
        }

        void push_front(const T &val)
        {
            insert(begin(), val);
        }

        void pop_back()
        {
            erase(--end());
        }
        void pop_front()
        {
            erase(begin());
        }

        bool empty()
        {
            return _size == 0;
        }

        size_t size()
        {
            return _size;
        }
        void print()
        {
            for (auto &e : *this)
            {
                std::cout << e << " ";
            }
            std::cout << std::endl;
        }
    };

}

上述代码以list为例即封装了普通的迭代器,还使用普通的迭代器适配出了反向迭代器。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐