M的编程备忘录之C++——List

目录

1、list的认识和使用

1.1、list的认识

1.2、list的使用

1.2.1、list的构造

1.2.2、list迭代器使用

 1.2.3、list的容量

1.2.4、list的元素访问

1.2.5、list的增删查改

1.2.6、list的迭代器失效

2、模拟实现

 3、list与vector的对比


1、list的认识和使用

1.1、list的认识

        1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
        2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
        3. list与 forward_list 非常相似:最主要的不同在于 forward_list 是单链表,只能朝前迭代
        4. 与其他的序列式容器相比 (array vector deque) list 通常在任意位置进行插入、移除元素的执行效率更好。
        5. 与其他序列式容器相比, list forward_list 最大的缺陷是不支持任意位置的随机访问

1.2、list的使用

1.2.1、list的构造

构造函数接口说明
list()
构造空的 list
list (size_type n, const value_type& val = value_type())
构造的 list 中包含 n 个值为 val 的元素
list (const list& x)
拷贝构造函数
list (InputIterator fifirst, InputIterator last)
[fifirst, last) 区间中的元素构造 list

1.2.2、list迭代器使用

接口名接口说明
begin()
返回第一个元素的迭代器
end()
返回最后一个元素下一个位置的迭代器
rbegin()
返回第一个元素的 reverse_iterator, end 位置的上一个
rend()
返回最后一个元素下一个位置的 reverse_iterator, begin 位置的上一个

 1.2.3、list的容量

接口名接口说明
empty()
检测 list 是否为空,是返回 true ,否则返回 false
size()
返回 list 中有效节点的个数

1.2.4、list的元素访问

接口名接口说明
front()返回list的第一个节点中值的引用
back()返回list的最后一个节点中值的引用

1.2.5、list的增删查改

接口名接口说明
push_front
list 首元素前插入值为 val 的元素
pop_front
删除 list 中第一个元素
push_back
list 尾部插入值为 val 的元素
pop_back
删除 list 中最后一个元素
insert
list position 位置中插入值为 val 的元素
erase
删除 list position 位置的元素
swap
交换两个 list 中的元素
clear
清空 list 中的有效元素

1.2.6、list的迭代器失效

        迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

2、模拟实现

// 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;
    };

    //List的迭代器类
    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)
        {}

        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);
            *this--;
            return tmp;
        }

        bool operator!=(const Self& l)
        {
            return _pNode != l._pNode;
        }
        bool operator==(const Self& l)
        {
            return _pNode == l._pNode;
        }
        
 
        PNode _pNode;
    };

    //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()
        {
            _pHead = new Node();
            _pHead->_pNext = _pHead;
            _pHead->_pPre = _pHead;
        }

        list(int n, const T& value = T())
        {
            CreateHead();
            while (n--)
            {
                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();
            list<T> tmp(l.begin(), l.end());
            swap(tmp);
        }

        list<T>& operator=(list<T> l)
        {
            swap(l);
            return *this;
        }

        ~list()
        {
            clear();
            delete _pHead;
            _pHead = nullptr;
        }
        
        // List Iterator
        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);
        }

        // List Capacity
        size_t size()const
        {
            PNode cur = _pHead;
            size_t cnt = 0;
            cur = cur->_pNext;
            while (cur != _pHead)
            {
                cnt++;
                cur = cur->_pNext;
            }
            return cnt;
        }

        bool empty()const
        {
            if (_pHead->_pNext == _pHead)
            {
                return true;
            }
            return false;
        }

        // 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(begin(), 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 Node(val);
            PNode cur = pos._pNode;
            PNode pre = cur->_pPre;

            pre->_pNext = newnode;
            newnode->_pPre = pre;
            newnode->_pNext = cur;
            cur->_pPre = newnode;
            
            return iterator(newnode);
        }

        // 删除pos位置的节点,返回该节点的下一个位置
        iterator erase(iterator pos)
        {
            assert(pos != _pHead);
            PNode cur = pos._pNode;
            PNode pre = cur->_pPre;
            PNode next = cur->_pNext;

            pre->_pNext = next;
            next->_pPre = pre;
            
            delete cur;
            return iterator(next);
        }

        void clear()
        {
            iterator it = begin();
            while (it != end())
            {
                it = erase(it);
            }
        }

        void swap(list<T>& l)
        {
            std::swap(_pHead, l._pHead);
        }
    private:
        void CreateHead()
        {
            _pHead = new Node();
            _pHead->_pNext = _pHead;
            _pHead->_pPre = _pHead;
        }
        PNode _pHead;
    };

 3、list与vector的对比

vectorlist
动态顺序表,一段连续空间
带头结点的双向循环链表
随机访问
支持随机访问,访问某个元素效率 O(1)
不支持随机访问,访问某个元素 效率 O(N)
插入和删除
任意位置插入和删除效率低,需要搬移元素,时间复杂
度为 O(N) ,插入时有可能需要增容,增容:开辟新空
间,拷贝元素,释放旧空间,导致效率更低
任意位置插入和删除效率高,不 需要搬移元素,时间复杂度为 O(1)

空间利用率

底层为连续空间,不容易造成内存碎片,空间利用率
高,缓存利用率高
底层节点动态开辟,小节点容易 造成内存碎片,空间利用率低, 缓存利用率低
迭代器
原生态指针
对原生态指针 ( 节点指针 ) 进行封装
迭代器失效
在插入元素时,要给所有的迭代器重新赋值,因为插入
元素有可能会导致重新扩容,致使原来迭代器失效,删
除时,当前迭代器需要重新赋值否则会失效
插入元素不会导致迭代器失效, 删除元素时,只会导致当前迭代 器失效,其他迭代器不受影响
使用场景
需要高效存储,支持随机访问,不关心插入删除效率
大量插入和删除操作,不关心随 机访问

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值