[cpp-->list]

本文详细介绍了C++中list容器的接口,包括构造、修改和操作方法,如构造函数、assign、push_front/push_back、pop_front/pop_back、insert、erase、resize、clear等。同时,文章还探讨了模拟实现list时的难点,如迭代器的实现、双向链表的管理以及操作,并提供了部分代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、接口介绍

1.构造

 //无参构造
    list<int> lt1;
    //n个val构造
    list<int> lt2(3, 10);
    
    //任意类型的迭代器区间构造
    int arr[] = { 3,5,1,7,9,10 };
    list<int> lt3(arr, arr + sizeof(arr) / sizeof(arr[0]));
    
    //拷贝构造
    list<int> lt4(lt3);
    
    //赋值构造
    list<int> lt5;
    lt5 = lt4;

2.修改

	int a1[] = { 4,3,5,2,7,9,10 };
    list<int> lt1(a1,a1+sizeof(a1)/sizeof(a1[0]));
    int a2[] = { 14,13,15,12,17,19,11 };
    //用任意类型的迭代器区间替换lt1的内容,并调整链表大小
    lt1.assign(a2, a2 + sizeof(a2) / sizeof(a2[0]));
    
    //用n个val替换lt1的内容,并调整链表大小
    lt1.assign(3,8);


    int a1[] = { 4,3,5,2,7};
    list<int> lt;
    //头插,头删
    lt.push_front(4);
    lt.pop_front();
    
    //尾插,尾删
    lt.push_back(5);
    lt.pop_back();


    //任意迭代器位置插入val
    lt.insert(lt.begin(), 4);
    //任意迭代器位置插入n个val
    lt.insert(lt.begin(), 3, 4);
    //在任意迭代器位置,插入一个任意类型的迭代器区间
    list<string> lt1;
    string s("hello world");
    lt1.insert(lt1.begin(),s.begin(), s.end());
    
    //删除任意迭代器位置的val
    lt.erase(lt.begin());
    //删除任意迭代器区间的val
    lt.erase(++lt.begin(), --lt.end());
    
	//变更链表的size,并初始化多余的空间
    lt.resize(3, 8);
    //清空
    lt.clear();

3.操作

 	int a1[] = { 4,3,5,2,7};
    list<int> lt1(a1,a1+sizeof(a1)/sizeof(a1[0]));
    
    //将lt2的内容转移至lt1的任意迭代器位置
    list<int> lt2(5, 7);
    lt1.splice(++lt1.begin(), lt2);
    //将lt3的任意迭代器位置的val转移至lt1的任意迭代器位置
    list<int> lt3(5, 8);
    lt1.splice(lt1.begin(), lt3,lt3.begin());
    //将lt4的任意迭代器区间的val转移至lt1的任意迭代器位置
    list<int> lt4(5, 9);
    lt1.splice(lt1.begin(), lt4,lt4.begin(),lt4.end());
    
	//查找val并删除
    lt1.remove(3);

	//排序,效率极低,一般使用算法库中的sort
	struct greate
	{
	    bool operator()(int x,int y)
	    {
	        return x > y;
	    }
	};
    int a1[] = { 4,3,5,2,7};
    list<int> lt1(a1,a1+sizeof(a1)/sizeof(a1[0]));
    lt1.sort(greate());


    //归并之前两个链表必须有序,不然会抛异常
    int a1[] = { 4,3,5,2,7 };
    list<int> lt1(a1,a1+sizeof(a1)/sizeof(a1[0]));
    lt1.sort();
    int a2[] = { 14,1,15,2,17 };
    list<int> lt2(a2, a2 + sizeof(a2) / sizeof(a2[0]));
    lt2.sort();
    //归并后lt2的链表被清空
    lt1.merge(lt2);

    //逆置
    lt1.reverse();

二、模拟实现

1.实现难点

因为在列表的头初始化时要用到无参构造,插入新节点时要用到带参构造,所以要给node节点全缺省构造.

list的初始化,出了赋值构造,其他的构造都需要先初始化头结点.

因为是双向带头循环链表,所以迭代器的头是head的下一个位置,尾是head的位置,插入是在节点之前插入,删除是删除当前节点,end()节点不能删除.

list的迭代器是双向迭代器,有些算法中要求使用随机迭代器,比如sort排序list不能使用.const迭代器不能直接加const,会导致迭代器的pnode的地址不能被修改,而const迭代器的初衷是想让,pnode指向的内容不能修改,所以要控制和->重载的常性.但是又需要可修改和不可修改两种实现,不想代码冗余就必须增加两个模板参数,一个控制pnode的data,一个控制pnode的data的地址.

2.代码实现

#pragma once
#include <iostream>
#include <cassert>
#include<algorithm>
using namespace std;

namespace kk
{
    template <class T>
    //节点结构
    struct listNode
    {
        listNode<T>* _next;
        listNode<T>* _previous;
        T _data;
        //在插入新节点的时候要用到带参构造,链表初始化要用到无参构造
        listNode(const T& data=T())
            :_data(data),_next(nullptr),_previous(nullptr)
        {}
    };
    template <class T, class ref, class ptr>
    struct listIterator
    {
        typedef listNode<T> node;
        typedef listIterator<T, ref, ptr> self;
        node* _pnode;
        listIterator(node* pnode)
            :_pnode(pnode)
        {}
        ref operator*()
        {
            return _pnode->_data;
        }
        ptr operator->()
        {
            return &_pnode->_data;
        }
        self& operator++()
        {
            _pnode = _pnode->_next;
            return *this;
        }
        self operator++(int)
        {
            /*这里用到的是默认拷贝构造,因为没有写析构所以不会释放两次空间
            迭代器不需要释放节点空间,迭代器只是用来包装访问节点的各种行为方法
            ,并没有控制链表,释放节点是链表的事情*/
            self tmp(*this);
            _pnode = _pnode->_next;
            return tmp;
        }
        self& operator--()
        {
            _pnode = _pnode->_previous;
            return *this;
        }
        self operator--(int)
        {
            self tmp(*this);
            _pnode = _pnode->_previous;
            return tmp;
        }
        bool operator!=(const self& s)
        {
            //比较的是节点的地址
            return _pnode != s._pnode;
        }
        bool operator==(const self& s)
        {
            return _pnode == s._pnode;
        }
    };
    template <class T>
    class list
    {
        typedef listNode<T> node;
    public:
        typedef listIterator<T, T&, T*> iterator;
        typedef listIterator<T, const T&, const T*> const_iterator;
        iterator begin()
        {
            /*○(尾)<-->1(头)<-->2<-->3 */
            return iterator(_phead->_next);
        }
        iterator end()
        {
            return iterator(_phead);
        }
        const_iterator begin() const
        {
            return const_iterator(_phead->_next);
        }
        const_iterator end() const
        {
            return const_iterator(_phead);
        }
        //初始化链表
        void emptyListInit()
        {
            _phead = new node;
            _phead->_next = _phead;
            _phead->_previous = _phead;
        }
        list()
        {
            emptyListInit();
        }
        //释放链表节点内存
        void clear()
        {
            iterator it = begin();
            while (it != end())
            {
                erase(it++);
            }
        }
        ~list()
        {
            clear();
            delete _phead;
            _phead = nullptr;
        }
        list(const list<T>& lt)
        {
            emptyListInit();
            for (auto e : lt)
            {
                push_back(e);
            }
        }
        void swap(list<T>& lt)
        {
            std::swap(_phead, lt._phead);
        }
        list& operator=(list<T> lt)
        {
            //赋值构造是默认构造之后的操作,所以不用初始化空链表
            swap(lt);
            return *this;
        }
        template <class inputIterator>
        list(inputIterator first, inputIterator last)
        {
            emptyListInit();
            while (first != last)
            {
                push_back(*(first++));
            }
        }
        void push_back(const T& data)
        {
            /*(插入)<-->○(end)<-->1(begin)<-->2<-->3 */
            insert(end(), data);
        }
        void pop_back()
        {
            /*○(end)<-->1(begin)<-->2<-->3(删除) */
            erase(--end());
        }
        void push_front(const T& data)
        {
            /*○(end)<-->(插入)<-->1(begin)<-->2<-->3 */
            insert(begin(), data);
        }
        void pop_front()
        {
            /*○(end)<-->1(删除)<-->2<-->3 */
            erase(begin());
        }
        void insert(iterator pos, const T& data)
        {
            //pos位置的节点
            node* cur = pos._pnode;
            //pos位置的前一个节点
            node* pre = pos._pnode->_previous;
            node* newNode = new node(data);
            //链接在cur和pre之间
            newNode->_next = cur;
            cur->_previous = newNode;
            
            newNode->_previous = pre;
            pre->_next = newNode;
        }
        iterator erase(iterator pos)
        {
            assert(pos != end());
            //pos之前的节点
            node* pre = pos._pnode->_previous;
            //pos之后的节点
            node* next = pos._pnode->_next;
            //链接pre和next
            pre->_next = next;
            next->_previous = pre;
            //释放pos位置的节点
            delete pos._pnode;
            pos._pnode = nullptr;
            //返回pos的下一个位置的节点
            return iterator(next);
        }
    private:
        node* _phead;
    };
    //构造+迭代器 测试
    void test_list1()
    {
        kk::list<int> lt;
        lt.push_back(1);
        lt.push_back(2);
        lt.push_back(3);
        lt.push_back(4);
        kk::list<int>::iterator it = lt.begin();
        while (it != lt.end())
        {
            cout << *(it++);
        }
        cout << endl;
        list<int> lt1;
        lt1 = lt;
        for (auto e : lt1)
        {
            cout << e;
        }
        cout << endl;
    }
    //任意位置删除测试
    void test_list2()
    {
        int arr[] = { 3,5,6,7,8,4,5,6,7 };
        list<int> lt(arr, arr + sizeof(arr) / sizeof(arr[0]));
        for (auto e : lt)
        {
            cout << e;
        }
        cout << endl;
        lt.erase(lt.begin());
        for (auto e : lt)
        {
            cout << e;
        }
        cout << endl;
        lt.erase(++lt.begin());
        for (auto e : lt)
        {
            cout << e;
        }
        cout << endl;
        lt.erase(--lt.end());
        for (auto e : lt)
        {
            cout << e;
        }
        cout << endl;
    }
    //清空测试
    void test_list3()
    {
        int arr[] = { 3,5,6,7,8,4,5,6,7 };
        list<int> lt(arr, arr + sizeof(arr) / sizeof(arr[0]));
        for (auto e : lt)
        {
            cout << e;
        }
        cout << endl;
        lt.clear();

        for (auto e : lt)
        {
            cout << e;
        }
        cout << endl;
        lt.push_back(1);
        lt.push_back(2);
        lt.push_back(3);
        lt.push_back(4);
        for (auto e : lt)
        {
            cout << e;
        }
        cout << endl;
    }
    //->重载测试
    struct AA
    {
        int _a=0;
        int _b = 0;
        AA(int a=0,int b=0)
            :_a(a)
            ,_b(b)
        {}
    };
    void test_list4()
    {
        list<AA> lt;
        lt.push_back(AA(1, 2));
        lt.push_back(AA(3, 4));
        auto it = lt.begin();
        cout << it->_a << " " << it->_b << endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值