C++ list的简易实现讲解

本文详细介绍了C++中list容器的底层结构,包括双向链表的节点设计,以及自定义迭代器类ListIterator的实现,展示了如何根据list的特点处理迭代操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.底层结构

list的底层是双向带头节点链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

二. 单个节点

    template<class T>
    struct ListNode
    {
        ListNode(const T& val = T())
        {
            _val = val;
        }
        ListNode<T>* _pPre;
        ListNode<T>* _pNext;
        T _val;
    };

上述代码是描述list 单个节点的 ,每个节点存储一个值,和指向前后节点的指针。

三.list 迭代器类(重点)

这个部分是主要难点,在vector中我们并未单独实现迭代器类,而是用typedef T* iterator,来自定义一个迭代器,而在list中我们需要自己实现一个iterator类,这是因为vector的底层是一片连续的空间,我们的++,--都能直接访问到下一个和前一个节点,但list由于底层是链表,++,--并不能直接访问前后节点,因此我们需要对该节点的指针进行封装,重载++,--等运算符,代码如下

    template<class T, class Ref, class Ptr>
    class ListIterator
    {
        typedef ListNode<T>* PNode;
        typedef ListIterator<T, Ref, Ptr> Self;
    public:
        PNode _pNode;
        ListIterator(PNode x)        
        {
            _pNode=x;
        }
        ListIterator(const Self& l)
        {
            _pNode = l._pNode;
        }
        Self& operator++()
        {
            _pNode = _pNode->_pNext;
            return *this;
        }
        Self operator++(int)
        {
            Self tmp(*this);
            _pNode = _pNode->_pNext;
            return tmp;
        }
        Self& operator--()
        {
            _pNode = _pNode->_pPre;
            return *this;
        }
        Self& operator--(int)
        {
            Self tmp(*this);
            _pNode = _pNode->_pPre;
            return tmp;
        }
        bool operator!=(const Self& l)
        {
            return _pNode->_val != l._pNode->_val;
        }
        bool operator==(const Self& l)
        {
            return _pNode == l._pNode->_val;
        }
        Ref operator*()
        {
            return _pNode->_val;
        }
        Ptr operator->()
        {
            return &(_pNode->_val);
        }

    };

这里有三个模板参数:class T, class Ref, class Ptr,其中 T 是用来表示list 节点存储值的类型。我们清楚迭代器有俩种类型:iterator,const_iterator,俩者的区别在于迭代器指向的能否修改,iterator可以修改,const_iterator不能,而具体的差别就在于*和->运算符重载上,iterator由于指向的可以修改,operator *()返回的是T&,operator->()返回的是T*, 而对于const_iterator指向的值不能修改 ,operator *()返回的是 const T&,  operator->() 返回的是const T*。因此俩者的代码具有很高的重复性,而 Ref和Ptr 就是为了实现俩者代码的复用。在list 类中,我们会有下面俩句代码

 typedef ListIterator<T, T&, T*> iterator;
 typedef ListIterator<T, const T&, const T*> const_iterator;

通过这俩句代码,我们对iterator和const_iterator传入不同的模板参数,从而实现俩者的不同。

三.list 类

 //list类
    template<class T>
    class list
    {
        typedef ListNode<T> Node;
        typedef Node* PNode;
    public:
        typedef ListIterator<T, T&, T*> iterator;
        typedef ListIterator<T, const T&, const T*> const_iterator;
    public:
        ///
        // List的构造

        list(){
            empty_init();
        }
        list(int n, const T& value = T())
        {
            empty_init();
            while (n--)
            {
                insert(_pHead->_pPre, value);
            }
        }
        template <class Iterator>
        list(Iterator first, Iterator last)
        {
            Iterator tmp = first;
            PNode node = _pHead->_pNext;
            while (tmp != last)
            {
                node->_val = *tmp;
                node = node->_pNext;
                ++tmp;
            }
        }
        list(const list<T>& l)
        {
            list tmp(l.begin(), l.end());
            std::swap(_pHead, l._pHead);
        }
        list<T>& operator=(const list<T> l)
        {
            list tmp(l);
            std::swap(_pHead, l._pHead);
            return *this;
        }
        ~list()
        {
            clear();
            delete _pHead;
        }


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


        ///
         //List Capacity
        size_t size()const
        {
            size_t i = 0;
            PNode tmp = _pHead->_pNext;
            while (tmp != _pHead)
            {
                i++;
                tmp = tmp->_pNext;
            }
            return i;
        }
        bool empty()const
        {
            return _pHead == _pHead->_pNext;
        }


        
        // List Access
        T& front()
        {
            return _pHead->_pNext->_val;
        }
        const T& front()const
        {
            return _pHead->_pNext->_val;
        }
        T& back()
        {
            return _pHead->_pPre->_val;
        }
        const T& back()const
        {
            return _pHead->_pPre->_val;
        }


        
        // 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)
        {
            PNode newnode = new ListNode<T>(val);
            PNode pre = pos._pNode->_pPre;
            
            pre->_pNext = newnode;
            newnode->_pPre = pre;
            newnode->_pNext = pos._pNode;
            pos._pNode->_pPre = newnode;
            return  newnode;
        }
        // 删除pos位置的节点,返回该节点的下一个位置
        iterator erase(iterator pos)
        {
            PNode pre = pos._pNode->_pPre;
            PNode next = pos._pNode->_pNext;
            pre->_pNext = next;
            next->_pPre = pre;
            delete pos._pNode;
            return next;
        }
        void clear()
        {
            PNode  tmp = _pHead;
            PNode tmp_next;
            while (tmp != _pHead)
            {
                tmp_next = tmp->_pNext;
                delete tmp;
                tmp = tmp_next;
            }
        }
        void swap(list<T>& l)
        {
            std::swap(_pHead, l->pHead);
        }
    private:
        void empty_init()
        {
            _pHead = (new ListNode<T>);
            _pHead->_pNext = _pHead;
            _pHead->_pPre = _pHead;
        }

        PNode _pHead;
    };

list 类的实现并无多少难点, 我们只要清楚双向带头节点链表结构的相应操作即可实现。

好了,一个简易的list实现就完成了,如果有问题和疑惑可以评论区提出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值