c++:list模拟实现

一、模拟实现list

要模拟实现list,必须要熟悉list的底层结构以及其接口的含义,大家可以看我关于list接口的博客c++:list-CSDN博客

1.1 list成员变量

list是一个双向带头链表,我们在定义成员变量时应该先定义出list单个的节点的类型。

1.1.1 list节点

cpp 复制代码
    // List的节点类
    template<class T>
    struct ListNode
    {
        //默认构造    T()是一个匿名对象
        ListNode(const T& val = T())
            :_pPre(nullptr)
            ,_pNext(nullptr)
            ,_val(val)
        {}
        ListNode<T>* _pPre;//指向上一个节点
        ListNode<T>* _pNext;//指向下一个节点
        T _val;             //节点的数据
    };

在c++中class 和struct 的主要区别就是struct 中的成员变量和成员函数的默认访问权限是public,而class中的成员变量和成员函数的默认访问权限是private,这里直接用struct更方便。

1.1.2 list的成员变量

cpp 复制代码
class List{
    typedef ListNode<T> Node;
    typedef Node* PNode;
    private:
        PNode _pHead;
        size_t _size = 0;
}

这里我们把节点类型重命名为Node,又把节点的指针重命名为PNode。List的成员变量只有一个头节点的指针和节点的数量。(List底层是一个带头双向链表

1.2 list的默认成员函数

1.2.1 默认构造

cpp 复制代码
 public:
        ///
        // List的构造
        //void CreateHead();
        //PNode _pHead;
        void CreateHead()
        {
            _pHead = new Node;
            _pHead->_pNext = _pHead;
            _pHead->_pPre = _pHead;
            _size = 0;
        }
        list()
        {
            CreateHead();
        }
        

1.2.2 构造函数

1.2.2.1 list中包含n个值为val的元素
cpp 复制代码
        list(int n, const T& value = T())
        {
            CreateHead();
            int i = n;
            while (i--)
            {
                push_back(value);
            }
        }

1.2.2.2 用迭代器区间初始化list

cpp 复制代码
        template <class Iterator>
        list(Iterator first, Iterator last)
        {
            CreateHead();
            while (first!=last)
            {
                push_back(*first);
                ++first;
            }
        }

1.2.3 拷贝构造

cpp 复制代码
        list(const list<T>& lt)
        {
            CreateHead();
            // 用l中的元素构造临时的temp,然后与当前对象交换
            list<T> temp(lt.begin(), lt.end());
            this->swap(temp);
        }
        void swap(list<T>& l)
        {
            std::swap(l._pHead, _pHead);
            std::swap(l._size, _size);
        }

1.2.4 赋值运算符重载

cpp 复制代码
        list<T>& operator=(list<T> lt)
        {
            swap(lt);
            return *this;
        }
        void swap(list<T>& l)
        {
            std::swap(l._pHead, _pHead);
            std::swap(l._size, _size);
        }

1.2.5 析构函数

cpp 复制代码
        ~list()
        {
            clear();
            delete _pHead;
            _pHead = nullptr;
        }
        void clear()
        {
            iterator it = begin();
            while (it != end())
            {
                //不用++防止迭代器失效
                it=erase(it);
            }
            _size = 0;
            _pHead = nullptr;
        }

1.3 list capacity

cpp 复制代码
        size_t size()const
        {
            return _size;
        }
        bool empty()const
        {
            return _size == 0;
        }

1.4 list 迭代器

正反向迭代器和const版本,反向迭代器是依靠正向迭代器实现,迭代器是通过对节点的指针进行封装,通过代码实现你想要的结果。

1.4.1 正向迭代器

cpp 复制代码
    template<class T, class Ref, class Ptr>
    struct ListIterator
    {
        typedef ListNode<T>* PNode;
        typedef ListIterator<T, Ref, Ptr> Self;
        //typedef ListIterator<T, T&, T*> iterator;
        //typedef ListIterator<T, const T&, const T&> const_iterator;
    public:
        ListIterator(PNode pNode = nullptr)
        {
            _pNode = pNode;
        }

        Ref operator*()
        {
            return _pNode->_val;
        }
        Ptr operator->()
        {
            return &(_pNode->_val);
        }
        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 l._pNode != _pNode;
        }
        bool operator==(const Self& l)
        {
            return l._pNode == _pNode;
        }
        PNode _pNode;
    };

1.4.2 begin,cbegin,end,cend,rbegin,rend,crbegin,crend

cpp 复制代码
        // List Iterator
    public:
        typedef ListNode<T> Node;
        typedef Node* PNode;
        typedef ListIterator<T, T&, T*> iterator;
        typedef ListIterator<T, const T&, const T*> const_iterator;   
        typedef ListReverseIterator<iterator,T, T&, T*> reverse_iterator;
        typedef ListReverseIterator<iterator,T, const T&, const T*> const_reverse_iterator;
        iterator begin()
        {
            return _pHead->_pNext;
        }
        iterator end()
        {
            return _pHead;
        }
        const_iterator begin()const
        {
            return _pHead->_pNext;
        }
        const_iterator end()const
        {
            return _pHead;
        }
        // ListreverseIterator
        reverse_iterator rbegin()
        {
            return reverse_iterator(end());
        }
        reverse_iterator rend()
        {
            return reverse_iterator(begin());
        }
        const_reverse_iterator rbegin()const
        {
            return reverse_iterator(end());
        }

        const_reverse_iterator rend()const
        {
            return reverse_iterator(begin());
        }

1.4.3 反向迭代器

cpp 复制代码
template<class iterator, class T, class Ref, class Ptr>
struct ListReverseIterator
{
public:
    typedef ListReverseIterator<iterator,T, Ref, Ptr> Self;
    ListReverseIterator(iterator it)
        :_it(it)
    {}

    Ref operator*()
    {
        //解引用不影响迭代器
        iterator tmp = _it;
        return *--tmp;
    }
    Ptr operator->()
    {
        return &(operator*());
    }
    Self& operator++()
    {
        --_it;
        return *this;
    }
    Self operator++(int)
    {
        Self tmp = _it--;
        return tmp;
    }
    Self& operator--()
    {
        ++_it;
        return *this;
    }
    Self& operator--(int)
    {
        Self tmp = --_it;
        return tmp;
    }
    bool operator!=(const Self& l)
    {
        return _it!= l._it;
    }
    bool operator==(const Self& l)
    {
        return _it == l._it;
    }
    
private:
    iterator _it;
};

1.5 list Modify

这里的erase和insert要返回一个迭代器来防止迭代器失效的问题。

cpp 复制代码
        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* tmp = pos._pNode;
            Node* prev = tmp->_pPre;

            newNode->_pNext = tmp;
            tmp->_pPre = newNode;
            
            newNode->_pPre = prev;
            prev->_pNext = newNode;

            _size++;
            return pos;
        }
        // 删除pos位置的节点,返回该节点的下一个位置
        iterator erase(iterator pos)
        {
            Node* tmp = pos._pNode;
            Node* tail = tmp->_pNext;
            Node* prev = tmp->_pPre;
            delete tmp;

            tail->_pPre = prev;
            prev->_pNext = tail;
            
            _size--;
            return iterator(tail);
        }

1.6 list Access

cpp 复制代码
        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的难点主要在迭代器的封装,反向迭代器的实现,和模板。

蟹蟹观看!点赞!关注!收藏!评论!一键三连!

相关推荐
星光樱梦8 分钟前
24. 正则表达式
c++
fathing9 分钟前
c# 调用c++ 的dll 出现找不到函数入口点
开发语言·c++·c#
前端青山30 分钟前
webpack指南
开发语言·前端·javascript·webpack·前端框架
nukix1 小时前
Mac Java 使用 tesseract 进行 ORC 识别
java·开发语言·macos·orc
XiaoLeisj1 小时前
【JavaEE初阶 — 多线程】内存可见性问题 & volatile
java·开发语言·java-ee
hope_wisdom1 小时前
C++网络编程之SSL/TLS加密通信
网络·c++·ssl·tls·加密通信
erxij1 小时前
【游戏引擎之路】登神长阶(十四)——OpenGL教程:士别三日,当刮目相看
c++·经验分享·游戏·3d·游戏引擎
Lizhihao_1 小时前
JAVA-队列
java·开发语言
林开落L2 小时前
前缀和算法习题篇(上)
c++·算法·leetcode
远望清一色2 小时前
基于MATLAB边缘检测博文
开发语言·算法·matlab