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接口

相关推荐
唐诺5 小时前
几种广泛使用的 C++ 编译器
c++·编译器
冷眼看人间恩怨6 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客6 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin6 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos7 小时前
c++---------数据类型
java·jvm·c++
十年一梦实验室8 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0018 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
这是我588 小时前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
fpcc8 小时前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
呆萌很8 小时前
C++ 集合 list 使用
c++