【C++】list(下):list类的模拟实现(含反向迭代器实现)

发布于:2025-03-17 ⋅ 阅读:(20) ⋅ 点赞:(0)


前言

list类的的模拟实现、ist的迭代器失效问题 以及 list与vector的对比。配套博客:【C++】list(上):list类的常用接口介绍


一、list类的模拟实现

1.list类的整体框架(声明)

#include <assert.h>
#include <algorithm>
#include <initializer_list>
using namespace std;

namespace zh
{
    // list的节点类
    template<class T>
    struct listnode
    {
        listnode(const T& val = T());

        listnode<T>* _pre;
        listnode<T>* _next;
        T _val;
    };

    // list的迭代器类
    template<class T,class reference,class pointer>
    struct listiterator
    {
        typedef listnode<T> node;
        typedef listiterator<T, reference, pointer> lsiter;

        listiterator(node* fnode = nullptr); // 默认构造
        listiterator(const lsiter& it); // 拷贝构造
        lsiter& operator=(const lsiter& it);
        reference operator*();
        pointer operator->();
        lsiter& operator++();
        lsiter operator++(int); // 后置++
        lsiter& operator--();
        lsiter operator--(int); // 后置--
        bool operator!=(const lsiter& it);
        bool operator==(const lsiter& it);

        node* _node;
    };

    // list类
    template<class T>
    class list
    {
        typedef listnode<T> node;
        void greate_sentinel_guard() // 创建哨兵卫
        {
            _head = new node;
            _head->_pre = _head;
            _head->_next = _head;
        }
    public:
        typedef listiterator<T, T&, T*> iterator;
        typedef listiterator<T, const T&, const T*> const_iterator;
        ///
        // List的构造
        list();
        list(int n, const T& value = T());
        
        template <class InputIterator>
        list(InputIterator first, InputIterator last);
        
        list(initializer_list<T> il);
        list(const list<T>& lst);
        list<T>& operator=(list<T> lst);
        ~list();

        ///
        // List Iterator
        iterator begin();
        iterator end();
        const_iterator begin() const;
        const_iterator end() const;

        ///
        // List Capacity
        size_t size()const;
        bool empty()const;

        
        // List Access
        T& front();
        const T& front() const;
        T& back();
        const T& back() const;

        
        // List Modify
        void push_back(const T& val);
        void pop_back();
        void push_front(const T& val);
        void pop_front();
        // 在pos位置前插入值为val的节点
        iterator insert(iterator pos, const T& val);
        // 删除pos位置的节点,返回该节点的下一个位置
        iterator erase(iterator pos);
        void clear();
        void swap(list<T>& lst);
    private:
        node* _head;
        size_t _size = 0;
    };
}

2.list的节点类模拟实现

namespace zh
{
    // list的节点类
    template<class T>
    struct listnode
    {
        listnode(const T& val = T())
            :_pre(nullptr)
            ,_next(nullptr)
            ,_val(val)
        { }

        listnode<T>* _pre;
        listnode<T>* _next;
        T _val;
    };
}    

3.list的迭代器类模拟实现

namespace zh
{
    // list的迭代器类
    template<class T,class reference,class pointer>
    struct listiterator
    {
        typedef listnode<T> node;
        typedef listiterator<T, reference, pointer> lsiter;

        listiterator(node* fnode = nullptr)
            :_node(fnode)
        { }

        listiterator(const lsiter& it)
        {
            _node = it._node;
        }

        lsiter& operator=(const lsiter& it)
        {
            _node = it._node;
            return *this;
        }

        reference operator*()
        {
            return _node->_val;
        }

        pointer operator->()
        {
            return &_node->_val;
        }

        lsiter& operator++()
        {
            _node = _node->_next;
            return *this;
        }

        lsiter operator++(int)
        {
            lsiter tmp(_node);
            _node = _node->_next;
            return tmp;
        }

        lsiter& operator--()
        {
            _node = _node->_pre;
            return *this;
        }

        lsiter operator--(int)
        {
            lsiter tmp(_node);
            _node = _node->_pre;
            return tmp;
        }

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

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

        node* _node;
    };
}

4.list类的常用接口的模拟实现

namespace zh
{
    //list类
    template<class T>
    class list
    {
        typedef listnode<T> node;
        void greate_sentinel_guard() // 创建哨兵卫
        {
            _head = new node;
            _head->_pre = _head;
            _head->_next = _head;
        }
    public:
        typedef listiterator<T, T&, T*> iterator;
        typedef listiterator<T, const T&, const T*> const_iterator;
        ///
        // List的构造
        list()
        {
            greate_sentinel_guard();
        }

        list(int n, const T& value = T())
        {
            greate_sentinel_guard();
            while (n--)
            {
                push_back(value);
            }
        }

        template <class InputIterator>
        list(InputIterator first, InputIterator last)
        {
            greate_sentinel_guard();
            while (first != last)
            {
                push_back(*first);
                first++;
            }
        }

        list(initializer_list<T> il)
        {
            greate_sentinel_guard();
            auto it = std::begin(il);
            while (it != std::end(il))
            {
                push_back(*it);
                it++;
            }
        }
        list(const list<T>& lst)
        {
            greate_sentinel_guard();
            for (const auto& it : lst)
            {
                push_back(it);
            }
        }

        list<T>& operator=(list<T> lst)
        {
            swap(lst);
            return *this;
        }

        ~list()
        {
            clear();
            delete _head;
            _head = nullptr;
        }

        ///
        // List Iterator
        iterator begin()
        {
            return iterator(_head->_next);
        }
        iterator end()
        {
            return iterator(_head);
        }
        const_iterator begin() const
        {
            return const_iterator(_head->_next);
        }
        const_iterator end() const
        {
            return const_iterator(_head);
        }

        ///
        // List Capacity
        size_t size()const
        {
            return _size;
        }
        bool empty()const
        {
            return _size == 0;
        }

        
        // List Access
        T& front()
        {
            assert(_size != 0);
            return *begin();
        }
        const T& front() const
        {
            assert(_size != 0);
            return *begin();
        }
        T& back()
        {
            assert(_size != 0);
            return *(--end());
        }
        const T& back() const
        {
            assert(_size != 0);
            return *(--end());
        }

        
        // List Modify
        void push_back(const T& val) 
        { 
            insert(end(), val); 
        }
        void pop_back() 
        { 
            erase(--end()); 
        }
        void push_front(const T& val) 
        { 
            insert(begin(), val); 
        }
        void pop_front() 
        { 
            erase(begin()); 
        }
        // 在pos位置前插入值为val的节点
        iterator insert(iterator pos, const T& val)
        {
            node* newnode = new node(val);
            node* pre = pos._node->_pre;
            pre->_next = newnode;
            newnode->_pre = pre;
            newnode->_next = pos._node;
            pos._node->_pre = newnode;
            _size++;
            return --pos;
        }
        // 删除pos位置的节点,返回该节点的下一个位置
        iterator erase(iterator pos)
        {
            assert(_size != 0);
            node* pre = pos._node->_pre;
            pre->_next = pos._node->_next;
            pos._node->_next = pre;
            delete pos._node;
            _size--;
            return iterator(pre->_next);
        }

        void clear()
        {
            node* cur = _head->_next;
            node* next = cur->_next;
            _head->_next = _head;
            _head->_pre = _head;
            while (cur != _head)
            {
                delete cur;
                cur = next;
                next = cur->_next;
            }
            _size = 0;
        }

        void swap(list<T>& lst)
        {
            std::swap(_head, lst._head);
            std::swap(_size, lst._size);
        }
        
private:
        node* _head;
        size_t _size = 0;
    };
}   

二、list的迭代器失效问题

list作为双向链表,它的迭代器失效情况比vector少很多。因为vector的元素是连续存储的,在插入元素时,可能会扩容导致内存重新分配,所有迭代器都失效,即使容量足够,插入位置及其之后的迭代器也会失效。而list的每个元素独立存储,通过指针连接,list的插入操作(如push_back、push_front、insert)不会使任何现有的迭代器失效;而删除操作(如erase、pop_back、pop_front等)会导致指向被删除元素的迭代器、指针和引用失效,但其他迭代器仍然有效。比如,删除一个节点后,指向它的迭代器就无效了,但其他节点的迭代器不受影响。

#include <list>
using namespace std;

int main()
{
	list<int> lst{ 1,2,3,4,5,6 };
	auto it = lst.begin();
	while (it != lst.end())
	{
		lst.erase(it);
		// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
		++it;
	}
	return 0;
}

在这里插入图片描述
修正后:

#include <list>
using namespace std;

int main()
{
	list<int> lst{ 1,2,3,4,5,6 };
	auto it = lst.begin();
	while (it != lst.end())
	{
		it = lst.erase(it);
		// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
	}
	return 0;
}

在这里插入图片描述

三、list与vector的对比

vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:

vector list
底层结构 动态顺序表(数组),一段连续空间 带哨兵节点的双向循环链表
元素访问 支持随机访问,访问某个元素效率O(1) 不支持随机访问,访问某个元素效率O(N)
插入和删除 任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低 任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1)
空间利用率 底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高 底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低
迭代器 原生态指针(早期库中实现方式) 对原生态指针(节点指针)进行封装
使用场景 需要高效存储,支持随机访问,不关心插入删除效率 大量插入和删除操作,不关心随机访问

四、反向迭代器(了解)

反向迭代器本质是⼀个适配器,使用模版实现,传递哪个容器的迭代器就可以封装适配出对应的反向迭代器。因为反向迭代器的功能跟正向的迭代器功能高度相似,只是遍历的方向相反,类似operator++ 底层调用迭代器的 operator-- 等,所以封装一下就可以实现。
在这里插入图片描述

namespace zh
{
    // 用正向迭代器适配出的反向迭代器
    template<class iterator, class reference, class pointer>
    struct reverseiterator
    {
        typedef reverseiterator<iterator, reference, pointer> reiter;

        reverseiterator(iterator it = iterator())
            :_it(it)
        { }

        reverseiterator(const reiter& it)
        {
            _it = it._it;
        }

        reiter& operator=(const reiter& it)
        {
            _it = it._it;
            return *this;
        }

        reference operator*()
        {
            iterator tmp = _it;
            tmp--;
            return *tmp;
        }

        pointer operator->()
        {
            return &(operator*());
        }

        reiter& operator++()
        {
            _it--;
            return *this;
        }

        reiter operator++(int)
        {
            reiter tmp(*this);
            _it--;
            return tmp;
        }

        reiter& operator--()
        {
            _it++;
            return *this;
        }

        reiter operator--(int)
        {
            reiter tmp(*this);
            _it++;
            return tmp;
        }

        bool operator!=(const reiter& it)
        {
            return _it != it._it;
        }

        bool operator==(const reiter& it)
        {
            return _it == it._it;
        }

        iterator _it;
    };

    // list类与反向迭代器相关联部分节选 //
    template<class T>
    class list
    {
        typedef listnode<T> node;
        void greate_sentinel_guard() // 创建哨兵卫
        {
            _head = new node;
            _head->_pre = _head;
            _head->_next = _head;
        }
    public:
        typedef listiterator<T, T&, T*> iterator;
        typedef listiterator<T, const T&, const T*> const_iterator;
        typedef reverseiterator<iterator, T&, T*> reverse_iterator;
        typedef reverseiterator<const_iterator, const T&, const T*> const_reverse_iterator;
        ///
        // List的构造
        list()
        {
            greate_sentinel_guard();
        }
        
        ///
        // List Iterator
        iterator begin()
        {
            return iterator(_head->_next);
        }
        iterator end()
        {
            return iterator(_head);
        }
        const_iterator begin() const
        {
            return const_iterator(_head->_next);
        }
        const_iterator end() const
        {
            return const_iterator(_head);
        }

        reverse_iterator rbegin()
        {
            return reverse_iterator(end());
        }
        reverse_iterator rend()
        {
            return reverse_iterator(begin());
        }
        const_reverse_iterator rbegin() const
        {
            return const_reverse_iterator(end());
        }
        const_reverse_iterator rend() const
        {
            return const_reverse_iterator(begin());
        }
        
    private:
        node* _head;
        size_t _size = 0;
    };
}

反向迭代器的operator*的实现方式比较特殊,内部访问的是迭代器当前位置的前⼀个位置。这个要结合容器中rbegin和rend实现才能看懂,rbegin返回的是封装end位置的反向迭代器,rend返回的是封装begin位置迭代器的反向迭代器,这里是为了实现出⼀个对称,所以解引用访问的是当前位置的前⼀个位置。
在这里插入图片描述