list 4个月前

编程语言
526
list

一、list要注意事项

1.迭代器失效


list没有增容销毁空间这一说,因此insert等插入不会导致失效 erase也是返回下一个位置的迭代器

if (*it % 2 == 0)
            it = l.erase(it); //erase 会导致迭代器失效
                              //空间被erase后不能再进行操作,即++,*;
        else
            ++it;

2.splic(连接两个链表)

list<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);
    l.push_back(4);

    list<int> lt;
    lt.push_back(10);
    lt.push_back(20);
    lt.push_back(30);
    lt.push_back(40);
    list<int>::iterator pos = l.begin();
    ++pos;

    l.splice(pos, lt); //在 l 链表中的pos位置插入lt链表
    Print_list(l); //1 10 20 30 40 2 3 4
    Print_list(lt); //lt插入过去就没了,成了l的一部分

二、模拟实现list

namespace 9TSe
{
    template<class T>  //一个节点的类
    struct __list_node
    {
        T _data;
        __list_node* _next;
        __list_node* _prev;

        __list_node(const T& x = T())
            :_data(x)
            ,_next(nullptr)
            ,_prev(nullptr)
        {}
    };


    template<class T, class Ref, class Ptr> //迭代器的类
    struct __list_iterator
    {
        typedef __list_node<T> Node;
        typedef __list_iterator<T, Ref, Ptr> Self;

        Node* _node; //创建一个新节点

        __list_iterator(Node* node) //构造节点
            :_node(node)
        {}

        Ref operator*()  //应该还有一个const类型的此函数,但要再写一个就要再创建一个const_iterator类其他都赋值,这两个加个const
        {                 //会导致代码冗余  T&
            return _node->_data;
        }

        Ptr operator->()  //同上,套用模板可以简写  T*
        {
            return &(_node->_data); //&取其地址以->,所以实际上使用应为 dit->->_year,只不过被编译器特殊处理优化
        }


        Self& operator++() //前置++,做到能像vector一样++就访问下一个数据
        {
            _node = _node->_next;
            return *this;
        }

        Self& operator++(int) //后置++
        {
            //__list_iterator tmp(*this);  
            Self tmp = *this;

            //_node = _node->_next;
            ++(*this);
            return tmp;
        }

        Self& operator--() //前置--
        {
            _node = _node->_prev;
            return *this;
        }

        Self& operator--(int) //后置--
        {
            Self tmp(*this);
            //_node = _node->_prev;
            --(*this);
            return *this;
        }

        bool operator!=(const Self& it) //迭代器循环时需要!=  记得加上const
        {
            return _node != it._node; //迭代器(两个指针)不相同
        }

        bool operator==(const Self& it)
        {
            return _node == it._node;
        }

    };


    template<class T> //链表的类
    class list
    {
    public:
        typedef __list_node<T> Node;
        typedef __list_iterator<T,T&,T*> iterator;
        typedef __list_iterator<T,const T&, const T*> const_iterator;

        iterator begin()
        {
            return iterator(_head->_next); //哨兵的下一位才是数据的第一位
        }

        iterator end()
        {
            return iterator(_head);  //哨兵就是最后一位
        }

        const_iterator begin()const
        {
            return const_iterator(_head->_next); 
        }

        const_iterator end()const
        {
            return const_iterator(_head);
        }

        list()
        {
            _head = new Node;
            _head->_next = _head;
            _head->_prev = _head;
        }

        list(const list<T>& lt)
        {
            _head = new Node;
            _head->_next = _head;
            _head->_prev = _head;

            /*const_iterator it = lt.begin();
            while (it != end())
            {
                push_back(*it);
                ++it;
            }*/

            for (auto e : lt)
            {
                push_back(e);
            }
        }

        /*list<T>& operator=(const list<T>& lt)
        {
            if (*this != &lt)
            {
                clear();
                for (auto& e : lt)
                {
                    push_back(e);
                }
            }
            return *this;
        }*/

        list<T>& operator=(list<T> lt)
        {
            swap(_head, lt._head); //交换指针指向的方向,即哨兵
            return *this;
        }


        ~list()
        {
            clear(); //清楚除哨兵外的数据
            delete _head;
            _head = nullptr;
        }

        void clear()
        {
            iterator it = begin();
            while (it != end())
            {
                erase(it++); //迭代器失效是因为,it被销毁后访问++或*,先调用重载++,后erase
            }
        }

        void push_back(const T& x)
        {
            //Node* tail = _head->_prev;
            //Node* newnode = new Node(x); //括号这里讲过
            //
            //tail->_next = newnode;
            //newnode->_prev = tail;
            //newnode->_next = _head;
            //_head->_prev = newnode;
            insert(end(), x); //插在哨兵前,哨兵前就是尾

        }

        void pop_back()
        {
            //erase(iterator(_head->_prev));
            erase(--end()); //哨兵前就是最后一个数据
        }

        void push_front(const T& x)
        {
            insert(begin(), x);
        }

        void pop_front()
        {
            erase(begin());
        }

        void insert(iterator pos, const T& x) //pos位置前插入
        {
            Node* newnode = new Node(x); //这里一定要初始值x
            Node* cur = pos._node;
            Node* prev = cur->_prev;
            cur->_prev = newnode;
            newnode->_next = cur; //1 2 3 3 4
            newnode->_prev = prev;
            prev->_next = newnode;
        }

        void erase(iterator pos)
        {
            assert(pos != end()); //不能删哨兵  1 2 3 3 4
            Node* cur = pos._node;
            Node* next = cur->_next;
            Node* prev = cur->_prev;
            delete cur; //可以不置空,出作用域自动销毁
            
            next->_prev = prev;
            prev->_next = next;
        }

    private:
        Node* _head;
    };






    void test_list1() //基本的遍历
    {
        list<int> lt;
        lt.push_back(1);
        lt.push_back(2);
        lt.push_back(3);
        lt.push_back(4);

        list<int>::iterator lit = lt.begin();
        while (lit != lt.end())
        {
            cout << *lit << " ";
            ++lit;
        }
        cout << endl;
    }



    struct Date
    {
        int _year = 0;
        int _month = 1;
        int _day = 1;
    };
    void test_list2() //cout类的数据
    {
        list<Date> dlt;
        dlt.push_back(Date());
        dlt.push_back(Date());

        list<Date>::iterator dit = dlt.begin();
        while (dit != dlt.end())
        {
            //cout << *dit << " "; //此时无法输出,一个类解引用怎么得不出想要的结果
            cout << dit->_year << "-" << dit->_month << "-" << dit->_day << endl; //这里->需要重载
                  //  dit->  返回 Date*
                  //所以实际上应写为 dit->->_year 为了可读性,编译器将其优化了,这样写反而会出错


            cout <<(*dit)._year << "-" << (*dit)._month << "-" << (*dit)._day << endl; //这样写也可以
                  //但是推荐->写法

            dit++;
        }
        cout << endl;
    }


    void print_list(const list<int>& lt)
    {
        list<int>::const_iterator lit = lt.begin();
        while (lit != lt.end())
        {
            //*lit = 1; //在修饰了lt为const,这一步却不报错且可以执行,不符合我们的要求
                        //此时加入const_iterator begin,end,重载*和&的修改
            cout << *lit << " ";
            ++lit;
        }
        cout << endl;
    }

    void test_list3() //测试部分操作接口
    {
        list<int> lt;
        lt.push_back(1);
        lt.push_back(2);
        lt.push_back(3);
        lt.push_back(4);

        print_list(lt);

        lt.pop_back();
        lt.pop_front();
        print_list(lt);

        lt.clear();
        print_list(lt);
    }

    void test_list4() //测试默认函数
    {
        list<int> lt1;
        lt1.push_back(1);
        lt1.push_back(2);
        lt1.push_back(3);
        lt1.push_back(4);

        list<int> lt2(lt1); //之所以在重载++地方报错是因为,clear时调用++,浅拷贝释放后无法++

        list<int> lt3;
        lt3 = lt2;

        print_list(lt2);
        print_list(lt3);
    }

    //Node* cur  和  iterator it   的区别
    //他们都指向同一个节点,在物理内存中他们都是存的这个节点的地址
    //但是他们类型不一样,他们的意义就不一样了
    //*cur表示的是指针的解引用       ,取到的值是节点
    //*it 表示去调用这个迭代器重载的*,返回的是节点中的值
}
image
EchoEcho官方
无论前方如何,请不要后悔与我相遇。
1377
发布数
439
关注者
2222794
累计阅读

热门教程文档

10.x
88小节
MyBatis
19小节
Linux
51小节
Djiango
17小节
HTML
32小节