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

相关推荐
羊小猪~~1 小时前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
脉牛杂德2 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz2 小时前
STL--哈希
c++·算法·哈希算法
CSUC2 小时前
【C++】父类参数有默认值时子类构造函数列表中可以省略该参数
c++
Vanranrr2 小时前
C++ QT
java·c++·qt
鸿儒5172 小时前
C++ lambda 匿名函数
开发语言·c++
van叶~3 小时前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
knighthood20013 小时前
解决:ros进行gazebo仿真,rviz没有显示传感器数据
c++·ubuntu·ros
半盏茶香4 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
小堇不是码农4 小时前
在VScode中配置C_C++环境
c语言·c++·vscode