STL之list

list简单介绍

  1. list是STL的一个序列式容器,底层的实现是一个双向链表,每个节点有两个指针分别指向前一个元素和后一个元素
  2. list在任意位置的插入与删除元素的效率很高,但是它访问元素的效率就相对比较低,它不支持任意位置的访问

list与vector的对比

这里不介绍list的使用,因为它和vector大部分的接口是一样的,不了解vector的可以去看

STL之vector

不同点

  • 迭代器失效的问题:vector的迭代器在插入删除时都可能导致迭代器失效但是list在插入时迭代器是不会失效的
  • vector访问元素的效率很高它能快速访问任意位置的数据,但是其插入与删除元素的效率极低,而list刚好与之相反
  • 需要大量随时访问元素时优先考虑使用vector,而要求插入删除的效率更高时优先考虑list

list的模拟实现

需要的类模板

  1. '节点类

    c++ 复制代码
        // List的节点类
       template<class T>
        struct ListNode
        {
            ListNode(const T& val = T())
                :_pPre(nullptr),
                _pNext(nullptr),
                _val(val)
            {}
            ListNode<T>* _pPre;
            ListNode<T>* _pNext;
            T _val;

    2.迭代器类

    c++ 复制代码
    //List的迭代器类
        template<class T, class Ref, class Ptr>
        class ListIterator
             template<class T, class Ref, class Ptr>
        class ListIterator
        {
            typedef ListNode<T>* PNode;
            typedef ListIterator<T, Ref, Ptr> Self;
        public:
            ListIterator(PNode pNode = nullptr)
                : _pNode(pNode)
            {
            }
            ListIterator(const Self& l)
                : _pNode(l._pNode)
            {}
            
     //运算符重载               
            T& operator*()
            {
                return _pNode->_val;
            }
            T* 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 _pNode != l._pNode;
            }
            bool operator==(const Self& l)
            {
                return _pNode == l._pNode;
            }
      
            PNode _pNode;

    为了减少代码的冗余所以将 ListNode*,ListIterator<T, Ref, Ptr>,用typedef进行封装

    3.list类

    c++ 复制代码
    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;
                private:
            void CreateHead()
            {
                _pHead = new Node;
                _pHead->_pPre = _pHead;
                _pHead->_pNext = _pHead;
            }
            PNode _pHead;

同意为了减少代码的冗余所以用typedef进行封装

构造与析构

调用接口CreateHead()和push_back()很容易实现构造

c++ 复制代码
 list()
        {
            CreateHead();
        }
        list(int n, const T& value = T())
        {
            CreateHead();
            for (int i = 0; i < n; ++i)
                push_back(value);
        }
 template <class Iterator>
        list(Iterator first, Iterator last)
        {
            CreateHead();
            while (first != last)
            {
                push_back(*first);
                ++first;
            }
        }
        list(const list<T>& l)
        {
            CreateHead();

            // 用l中的元素构造临时的temp,然后与当前对象交换
            list<T> temp(l.begin(), l.end());
            this->swap(temp);
        }
        list<T>& operator=(list<T> l)
        {
            this->swap(l);
            return *this;
        }
        ~list()
        {
            clear();
            delete _pHead;
            _pHead = nullptr;
        }

迭代器

两种迭代器运用函数的重载即可实现

c++ 复制代码
iterator begin()
        {
            return iterator(_pHead->_pNext);
        }
        iterator end()
        {
            return iterator (_pHead);
        }
        const_iterator begin() const
        {
            return const_iterator ( _pHead->_pNext);
        }
        const_iterator end() const
        {
            return const_iterator (_pHead);
        }

容量

c++ 复制代码
  size_t size()const
        {
            PNode cur = _pHead->_pNext;
            size_t count = 0;
            while (cur != _pHead)
            {
                count++;
                cur = cur->_pNext;
            }

            return count;
        }
        bool empty()const
        {
            return _pHead->_pNext == _pHead;
        }

获取元素

返回相应值即可

c++ 复制代码
 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;
        }

修改

c++ 复制代码
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()); 

运用迭代器和insert()erase()接口

insert的实现

c++ 复制代码
iterator insert(iterator pos, const T& val)
        {
            Node* pNewNode = new Node(val);
            Node* pCur = pos._pNode;
  
            pNewNode->_pPre = pCur->_pPre;
            pNewNode->_pNext = pCur;
            pNewNode->_pPre->_pNext = pNewNode;
            pCur->_pPre = pNewNode;
            return iterator(pNewNode);
        }

首先创建一个的节点Node让它的向前指针指向pos节点的前一个节点,它的向后指针指向pos位置的节点

然后再让pos位置的前一个节点的向后的指针指向新的节点Node,pos位置的向前指针指向新节点Node即可

erase的实现

c++ 复制代码
iterator erase(iterator pos)
        {
            Node* pDel = pos._pNode;
            Node* pRet = pDel->_pNext;
            pDel->_pPre->_pNext = pDel->_pNext;
            pDel->_pNext->_pPre = pDel->_pPre;
            delete pDel;
            return iterator(pRet);
        }

首先保存被删除节点的指针用pDel保存,因为erase返回的是被删除节点的下一个节点的迭代器所以我们也要将其保存在pRet中,然后就就简单了,将被删节点的后一个节点的向前指针指向被删节点的前一个节点,将被删节点的前一个节点的向后指针指向被删除指针的后面一个节点即可。

c++ 复制代码
void clear()
        {
            PNode cur = _pHead->_pNext;
            while (cur != _pHead)
            {
                _pHead->_pNext = cur->_pNext;
                delete cur;
                cur = _pHead->_pNext;
            }
            _pHead->_pNext = _pHead->_pPre = _pHead;
        }
        void swap(list<T>& l)
        {
            std::swap(_pHead, l._pHead);
        }

clear()遍历list删除即可,swap()用std的swap接口

相关推荐
小陈phd3 分钟前
Vscode LinuxC++环境配置
linux·c++·vscode
火山口车神丶18 分钟前
某车企ASW面试笔试题
c++·matlab
是阿建吖!43 分钟前
【优选算法】二分查找
c++·算法
努力进修1 小时前
“探索Java List的无限可能:从基础到高级应用“
java·开发语言·list
Ajiang28247353043 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
‘’林花谢了春红‘’7 小时前
C++ list (链表)容器
c++·链表·list
机器视觉知识推荐、就业指导9 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
阿龟在奔跑10 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
Yang.9911 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3