list

目录

迭代器

介绍

种类

本质

介绍

模拟实现

注意点

代码


迭代器

介绍

在C++中,迭代器(Iterators)是一种用于遍历容器(如数组、vector、list等)中元素的工具

无论容器的具体实现细节如何,访问容器中的元素的方法都是统一的,使用者不需要知道具体实现的细节

  • 迭代器的概念类似于指针,但迭代器更为通用,可以适用于各种不同类型的容器(且不同对象的迭代器,种类也不同)
  • 迭代器在算法函数中也可以使用,这样可以兼容不同的容器(比如sort,find),就可以使用通用的算法模板

种类

迭代器分为几种不同类型,每种类型对应不同的容器特性和访问方式:

  1. 输入迭代器(Input Iterator):仅支持从容器中读取数据,类似于只读操作。它们一次只能移动一个位置,不允许修改容器的元素。

  2. 输出迭代器(Output Iterator):仅支持向容器中写入数据,类似于只写操作。与输入迭代器类似,一次只能移动一个位置。

  3. 前向迭代器(Forward Iterator):支持读取和写入操作,并且可以多次遍历容器。每次移动一个位置。

  4. 双向迭代器(Bidirectional Iterator):与前向迭代器类似,但可以向前和向后移动,每次一个位置。

  5. 随机访问迭代器(Random Access Iterator):具有最强大的功能,可以在常量时间内跳转到容器中的任何位置,支持读取、写入和算术操作

  • 这几种迭代器互相有包含关系,比如可以使用双向迭代器的,也可以使用随机迭代器

  • 不同的迭代器用以支持遍历不同类型的容器,以及限制了算法函数兼容的容器类型(比如sort就不支持list类型)

  • 每个容器都有自己对应的迭代器类型

本质

实际上都是指针,有些容器的迭代器可以直接使用指针(eg:vector),但有些不行(eg: list)

  • list的物理空间并不连续,直接使用无法实现++的效果,其他功能也不行
  • 因此就需要创建一个类,来规定迭代器的操作

介绍

list是标准模板库(STL)提供的一个双向带头链表容器类


上面有说,list并不支持sort,但list内部有自己的sort

  • 虽然是这样没错,但既然不支持,自然有它的道理
  • 内部的sort在遇到大数据时,远不如 "将数据拷贝到vector中,由vector使用sort排序,再将排序后的数据恢复成list" 的效率高
  • 当然,小数据的时候就不需要这些麻烦的操作了,这时候内部的sort还是很方便嘟

模拟实现

注意点

  • 迭代器封装+结点封装(以及进行了重命名,会有各种嵌套)

  • 结点类 中有前后指针+数据,list类 中有头结点指针+结点个数,迭代器是结点指针包装后的产物

  • const迭代器的实现 (模板参数)

  • 两种迭代器 在list类中传参+重命名 实例化,可以传指针构造,也有拷贝构造

  • ' -> '符号的重载 (->重载函数返回指针 ,因此访问迭代器的实际语法应为 it -> ->begin(),是编译器简化成了只有一个->)

  • list的多种拷贝构造

代码

cpp 复制代码
#include <iostream>
#include <assert.h>
#include <string>

using namespace std;

namespace bit
{
    // List的节点类
    template <class T>
    struct ListNode // struct默认公有(因为不会有人去访问结点成员的)
    {
        typedef ListNode<T> *PNode;
        ListNode(const T &val = T())
            : _ppre(nullptr), _pnext(nullptr), _val(val){};

        PNode _ppre;
        PNode _pnext;
        T _val;
    };

    // List的迭代器类 -- 因为无法直接使用指针作为迭代器,需要手动添加功能
    template <class T, class Ref, class Ptr> // ref用于标记*时对象的const属性,ptr用于标记->时返回对象的const属性
    class ListIterator
    {
    public:
        typedef ListNode<T> *PNode;             // 指针重命名
        typedef ListIterator<T, Ref, Ptr> Self; // 迭代器重命名

        PNode _pNode; // 将指针作为迭代器的底层
    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;
        }
    };

    // list类
    template <class T>
    class mylist
    {
        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的构造
        mylist()
        {
            CreateHead();
        }
        mylist(int n, const T &value = T())
        {
            CreateHead();
            PNode p = _pHead;
            for (size_t i = 0; i < n; ++i)
            {
                push_back(value);
            }
            _size += n;
        }

        template <class Iterator>
        mylist(Iterator first, Iterator last)
        {
            CreateHead();
            while (first != last)
            {
                push_back(*first);
                ++first;
            }
        }

        mylist(const mylist<T> &l)
        {
            CreateHead();
            for (auto c : l)
            {
                push_back(c);
            }
        }
        mylist<T> &operator=(const mylist<T> l)
        {
            swap(l);
            return (*this);
        }
        ~mylist()
        {
            // clear();
            // delete[] _pHead;
            while (!empty())
            {
                erase(begin());
            }
        }

        // 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
        {
            return _size;
        }
        bool empty() const
        {
            return _size == 0;
        }

        // List Access
        T &front(){
            return *begin();
        }
        const T &front() const{
            return *begin();
        }
        T &back(){
            return *(--end());
        }
        const T &back() const{
            return *(--end());
        }

        // 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 cur = pos._pNode;
            PNode pre = cur->_ppre;
            PNode newnode = new Node(val);

            newnode->_pnext = cur;
            pre->_pnext = newnode;

            cur->_ppre = newnode;
            newnode->_ppre = pre;

            _size++;

            return newnode;
        }
        // 删除pos位置的节点,返回该节点的下一个位置
        iterator erase(iterator pos)
        {
            PNode cur = pos._pNode;
            PNode pre = cur->_ppre, next = cur->_pnext;
            pre->_pnext = cur->_pnext;
            cur->_pnext->_ppre = pre;
            delete cur;
            --_size;
            return next;
        }
        void clear()
        {
            PNode cur = _pHead->_pnext;
            while (cur != _pHead)
            {
                PNode tmp = cur;
                cur = cur->_pnext;
                delete tmp;
            }
            _size = 0;
            // iterator it = begin();
            // while (it != end())
            // {
            //     it = erase(it);
            // }
        }
        void swap(mylist<T> &l)
        {
            std::swap(_pHead, l._pHead);
            std::swap(_size, l._size);
        }

    private:
        void CreateHead()
        {
            _pHead = new Node;
            _pHead->_pnext = _pHead;
            _pHead->_ppre = _pHead;
            _size = 0;
        }
        PNode _pHead;
        size_t _size;
    };
};
相关推荐
爱吃生蚝的于勒2 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
workflower8 小时前
数据结构练习题和答案
数据结构·算法·链表·线性回归
一个不喜欢and不会代码的码农8 小时前
力扣105:从先序和中序序列构造二叉树
数据结构·算法·leetcode
No0d1es10 小时前
2024年9月青少年软件编程(C语言/C++)等级考试试卷(九级)
c语言·数据结构·c++·算法·青少年编程·电子学会
bingw011410 小时前
华为机试HJ42 学英语
数据结构·算法·华为
Yanna_12345611 小时前
数据结构小项目
数据结构
木辛木辛子12 小时前
L2-2 十二进制字符串转换成十进制整数
c语言·开发语言·数据结构·c++·算法
誓约酱12 小时前
(动画版)排序算法 -希尔排序
数据结构·c++·算法·排序算法
誓约酱13 小时前
(动画版)排序算法 -选择排序
数据结构·算法·排序算法
可别是个可爱鬼14 小时前
代码随想录 -- 动态规划 -- 完全平方数
数据结构·python·算法·leetcode·动态规划