C++ : list类及其模拟实现

目录

一、list的介绍和使用

list的介绍

list的使用

1.list的构造

构造函数

[2.list iterator 的使用](#2.list iterator 的使用)

[3.list capacity](#3.list capacity)

[4.list element access](#4.list element access)

[5.list modifiers](#5.list modifiers)

6.list的迭代器失效

二、list的模拟实现

要点

list类模拟实现部分接口全部代码展示


一、list的介绍和使用

list的介绍

1.list 是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。

2.list的底层是带头双向可循环链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

3.list和forward_list非常相似:最主要的不同在于forward_list 是单链表,只能朝前迭代,让其更简单高效。

4.与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。

5.与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间。

list的使用

1.list的构造

构造函数

(1)是指传来一个空指针,构造空的list

(2)指构造n个值为val的list

(3)用[first,last)中的元素构造list

(4)用x链表拷贝构造

2.list iterator 的使用

迭代器可以理解成一个指针,因为它封装了底层的逻辑,像指针一样使用。该指针指向list中的某个节点。begin就是指向第一个节点(非哨兵),end,返回最后一个元素下一个位置(就是哨兵位)。rbegin返回end位置,rend,返回begin位置。

注意:

begin和end是正向迭代器,对迭代器++,迭代器向后移动

rbegin和rend是反向迭代器,对迭代器++,迭代器向前移动

3.list capacity

empty 检查list是否是空链表

size 返回list中有效节点个数

4.list element access

front 返回list中,第一个节点的值的引用

back返回list中,最后一个节点的值的引用

5.list modifiers

模拟实现的话,掌握红框中常用的就好。

push_front 在list首节点前插入 值为val的节点

pop_front 删除list首节点

push_back 在list最后一个元素后插入值为val的节点

pop_back 删除list尾结点

insert 在pos位置插入一个值为val的节点

erase 删除pos位置的节点

swap 交换两个list中的元素

clear 清除list中的有效节点

6.list的迭代器失效

迭代器失效是指迭代器指向的节点无效,也就是该节点被删除了,用户不会再有该节点的访问权限。因为list的底层是带头双向循环链表,所以在list中进行插入时是不会导致list迭代器失效的,只有在删除时才会失效,并且失效的只有被删除节点的迭代器,其他节点的迭代器不会受到影响。

在逐个(调用erase函数时,参数)用后置++,不用前置++。表示删除以后,it又被重新赋值了。

二、list的模拟实现

要点

1.list要实现节点链表 还有迭代器 三个部分,**分别建立三个类模板。这是为了提高类的复用性。**封装在自己的命名空间里。

2.单个节点的结构体是公有的开放的,因为要在其他类里经常调用。所以得开放。包含val,前指针和后指针,以及构造函数。

cpp 复制代码
 // 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;
 };

3.写迭代器的类时**,迭代器指针也要设置为开放的**,为了后面在list类中erase pos位置和insert pos位置可以访问。迭代器的类模板是这样的。

Ref 和Ptr分别是迭代器返回的引用类型 和 迭代器返回的指针类型。

如果写T& 和T*,会限制迭代器返回的类型,这样想要返回const T& 和const T* 也无法更改。而Ref可以使你在实例化的时候就可以选择返回类型是什么。

cpp 复制代码
//List的迭代器类
template<class T, class Ref, class Ptr>
class ListIterator
{
    typedef ListNode<T>* PNode;
    typedef ListIterator<T, Ref, Ptr> Self;//加了Ref和Ptr后,代码的灵活性提高
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 ptmp(*this);
        _pNode = _pNode->_pNext;
        return ptmp;
    }
    Self& operator--()
    {
        _pNode = _pNode->_pPre;
        return *this;
    }
    Self& operator--(int)
    {
        Self ptmp(*this);
        _pNode = _pNode->_pPre;
        return ptmp;
    }
    bool operator!=(const Self& l)
    {
        return _pNode != l._pNode;
    }
    bool operator==(const Self& l)
    {
        return _pNode == l._pNode;
    }
public:
    PNode _pNode;
};

list类模拟实现部分接口全部代码展示

cpp 复制代码
#pragma once
#include<iostream>
#include <assert.h>
using namespace std;


namespace ting
{
    // 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;//加了Ref和Ptr后,代码的灵活性提高
    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 ptmp(*this);
            _pNode = _pNode->_pNext;
            return ptmp;
        }
        Self& operator--()
        {
            _pNode = _pNode->_pPre;
            return *this;
        }
        Self& operator--(int)
        {
            Self ptmp(*this);
            _pNode = _pNode->_pPre;
            return ptmp;
        }
        bool operator!=(const Self& l)
        {
            return _pNode != l._pNode;
        }
        bool operator==(const Self& l)
        {
            return _pNode == l._pNode;
        }
    public:
        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()
        {
            //处理私设的变量
            CreateHead();
           
        }
        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=(const list<T> l)
        {
            swap(l);
            return *this;
        }
        ~list()
        {
            clear();
            delete _pHead;
            _pHead = nullptr;

        }

        

        ///
        // List Iterator
        iterator begin()
        {
            return iterator(_pHead->_pNext);//因为_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
        {
            size_t n = 0;
            for (auto it = begin(); it != end(); ++it)
            {
                ++n;
            }
            return n;
        }
        bool empty()const
        {
            return _pHead->_pNext == _pHead;
        }


        
        // 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(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)
        {
            PNode newnode = new Node(val);
            newnode->_pNext = pos._pNode;
            newnode->_pPre = pos._pNode->_pPre;

            newnode->_pPre->_pNext = newnode;
            pos._pNode->_pPre = newnode;
            return iterator(newnode);
        }

        iterator erase(iterator pos)
        {
            assert(pos != end());
            PNode nextNode = pos._pNode->_pNext;
            pos._pNode->_pPre->_pNext = pos._pNode->_pNext;
            pos._pNode->_pNext->_pPre = pos._pNode->_pPre;
            delete pos._pNode;
            return iterator(nextNode);
        }

        void clear()
        {
            while (!empty())
            {
                pop_back();
            }
        }
        void swap(list<T>& l)
        {
            std::swap(_pHead, l._pHead);
        }
    private:
        void CreateHead()
        {
            _pHead = new Node();
            _pHead->_pPre = _pHead;
            _pHead->_pNext = _pHead;
        }
        PNode _pHead;
    };
};
相关推荐
Ajiang28247353042 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空2 小时前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10225 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
‘’林花谢了春红‘’6 小时前
C++ list (链表)容器
c++·链表·list
----云烟----7 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024067 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic7 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it7 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康7 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神8 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式