讨论stl链表

讨论链表

  • list迭代器失效
  • list的模拟实现
    • 创建结点类
    • 链表迭代器
    • 完成实现代码
  • list与vector

链表是一个序列容器,在任意位置都可以用常数时间插入或者删除,并且可以在两个方向进行迭代。

链表定义

list迭代器失效

迭代器失效指迭代器所指向的结点无效,即该结点被删除了。

  • list的底层结构是双向带头循环链表,因此向list中插入数据是不会造成迭代器失效。
  • 但删除数据时,指向删除结点的迭代器会失效,其他迭代器不会受影响。

list的模拟实现

创建结点类

  • 链表是由一个一个结点组成,结点中存放储存的元素已经指向下一个以及前一个的指针。
template<class T>
struct list_node {
    T _val;
    list_node<T> *_prev;
    list_node<T> *_next;

    list_node(const T &val = T())
            : _val(val), _prev(nullptr), _next(nullptr) {}
};

链表迭代器

  • 链表的迭代器不同于顺序表。顺序表的迭代器可以直接返回头部和尾部指针的位置。++操作只需要移动相应字节数的指针即可完成。

顺序表迭代器

  • 链表迭代器++操作不能依靠简单的指针++完成,因为不是连续空间,因此需要封装一层结点结构,以_node = _node->next来达到++的效果。
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 = nullptr)
            : _node(node) {}

    self &operator++() {
        _node = _node->_next;
        return *this;
    }

    self operator++(int) {
        self tmp(*this);
        _node = _node->next;
        return tmp;
    }

    self &operator--() {
        _node = _node->_prev;
        return *this;
    }

    self operator--(int) {
        self tmp(*this);
        _node = _node->_prev;
        return tmp;
    }

    Ref operator*() {
        return _node->_val;
    }

    Ptr operator->() {
        return &_node->_val;
    }

    bool operator!=(const self &s) {
        return _node != s._node;
    }

    bool operator==(const self &s) {
        return _node == s._node;
    }
};
  • 其中RefPtr模板为传入引用或者指针对象区分const和非const的模板。

完成实现代码

namespace max {
    template<class T>
    struct list_node {
        T _val;
        list_node<T> *_prev;
        list_node<T> *_next;

        list_node(const T &val = T())
                : _val(val), _prev(nullptr), _next(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 = nullptr)
                : _node(node) {}

        self &operator++() {
            _node = _node->_next;
            return *this;
        }

        self operator++(int) {
            self tmp(*this);
            _node = _node->next;
            return tmp;
        }

        self &operator--() {
            _node = _node->_prev;
            return *this;
        }

        self operator--(int) {
            self tmp(*this);
            _node = _node->_prev;
            return tmp;
        }

        Ref operator*() {
            return _node->_val;
        }

        Ptr operator->() {
            return &_node->_val;
        }

        bool operator!=(const self &s) {
            return _node != s._node;
        }

        bool operator==(const self &s) {
            return _node == s._node;
        }
    };

    template<class T>
    class list {
        typedef list_node<T> node;
        typedef __list_iterator<T, T &, T *> iterator;
        typedef __list_iterator<T, const T &, const T *> const_iterator;
    public:

        void empty_init() {
            _head = new node();
            _head->_next = _head;
            _head->_prev = _head;

            _size = 0;
        }

        list() {
            empty_init();
        }

        list(int n, const T &val = T()) {
            empty_init();
            for (int i = 0; i < n; ++i) {
                push_back(val);
            }
        }

        template<class Iterator>
        list(Iterator first, Iterator last) {
            empty_init();
            while (first != last) {
                push_back(*first);
                ++first;
                ++_size;
            }
        }

        list(const list<T> &lt) {
            empty_init();

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

        void swap(list<T> &tmp) {
            std::swap(_head, tmp._head);
            std::swap(_size, tmp._size);
        }

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

        ~list() {
            clear();
            delete _head;
            _head = nullptr;
        }


        void push_back(const T &val) {
            node *newNode = new node(val);
            node *end = _head->_prev;

            end->_next = newNode;
            newNode->_prev = end;
            newNode->_next = _head;
            _head->_prev = newNode;

            ++_size;
        }

        void push_front(const T &val) {
            node *newNode = new node(val);
            node *next = _head->_next;

            newNode->_next = next;
            next->_prev = newNode;
            _head->_next = newNode;
            newNode->_prev = _head;
        }

        void pop_back() {
            assert(_head->_next != _head);

            node *del = _head->_prev;
            _head->_prev = del->_prev;

            del->_prev->_next = _head;

            delete del;
            del = nullptr;
            --_size;
        }

        void pop_front() {
            assert(_head->_next != _head);

            node *del = _head->_next;

            _head->_next = del->_next;
            del->_next->_prev = _head;

            delete del;
            del = nullptr;
            --_size;
        }

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

        iterator insert(iterator pos, const T &val) {
            node *newNode = new node(val);
            node *prev = pos._node->_prev;

            prev->next = newNode;
            newNode->_prev = prev;
            newNode->_next = pos._node;
            pos._node->_prev = newNode;

            ++_size;

            return iterator(newNode);
        }

        iterator erase(iterator pos) {
            assert(_head != _head->_next);
            node *cur = pos._node;
            node *next = cur->_next;
            node *prev = cur->_prev;

            prev->_next = next;
            next->_prev = prev;

            delete cur;
            cur = nullptr;
            --_size;

            return iterator(next);
        }

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

        size_t size() const {
            return _size;
        }

    private:
        node *_head;
        size_t _size;
    };
}

list与vector

  • vectorlist底层结构不同,因此在使用场景上存在一定差异。
vectorlist
底层结构动态顺序表,一段连续的空间。带头双向循环链表
随机访问支持随机访问,效率为O(1)。不支持随机访问,访问某个元素的效率为O(N)。
插入和删除尾插和尾删时效率是O(1)。除此之外插入删除的效率都很低,因为需要移动数据,若插入大量数据还涉及到扩容,异地扩容需要拷贝元素和释放旧空间,效率很低。任意位置插入和删除数据效率为O(1)。不需要移动数据。
空间利用率底层为连续空间,不容易产生内存碎片,利用率高,缓存利用率高。底层为动态开辟的小结点,容易造成内存碎片,空间利用率低,缓存利用率低。
迭代器原生态指针。对原生态指针进行封装。
迭代器失效插入元素时可能会造成迭代器失效,因为可能会异地扩容。删除元素时当前迭代器会失效。插入元素时不会造成迭代器失效,删除元素时会造成当前迭代器失效,其他迭代器不受影响。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/756095.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构7---图

一、定义 对于图的定义&#xff0c;我们需要明确几个注意的地方:一线性表中我们把数据元素叫元素&#xff0c;树中叫结点&#xff0c;在途中数据元素我们则称之为顶点(Vertex)。 对于图的定义&#xff0c;我们需要明确几个注意的地方: 线性表中我们把数据元素叫元素&#xf…

通过systemctl启停tomcat

目录 目的.service配置文件的结构介绍实验步骤1. 安装java2. 二进制安装tomcat3. 编写/usr/systemd/system/tomcat.service文件4. 测试启动关闭 目的 通过二进制安装的tomcat&#xff0c;只能通过tomcat文件目录下的.sh脚本进行启停。 而我们一般使用的服务&#xff0c;是通过…

kubuadm 方式部署 k8s 集群

准备三台机器 主机名IP地址CPU/内存角色K8S版本Docker版本k8s231192.168.99.2312C4Gmaster1.23.1720.10.24k8s232192.168.99.2322C4Gwoker1.23.1720.10.24k8s233192.168.99.2332C4Gwoker1.23.1720.10.24 需要在K8S集群各节点上面安装docker&#xff0c;如未安装则参考 …

探究互联网领域知识,解密数字化时代神秘面纱

随着信息时代的不断发展&#xff0c;互联网的发展呈现出爆炸式的增长&#xff0c;以至于引起广泛的关注和深入的探究。互联网作为一个庞大的网络体系&#xff0c;涵盖着无穷无尽的信息和知识&#xff0c;其背后的科技和应用已经改变了人们的生活&#xff0c;产生了翻天覆地的变…

使用java代码实现GUI画面的简易项目操作

要使用Java创建一个图形用户界面&#xff08;GUI&#xff09;&#xff0c;我们可以使用Swing库&#xff0c;它是Java提供的一个标准GUI工具包。以下是一个简单的Java Swing程序示例&#xff0c;它创建了一个窗口&#xff08;JFrame&#xff09;&#xff0c;并在其中添加了一个标…

Ubuntu系统,实现FastDDS的源码编译

目录 一、Ubuntu系统介绍二、FastDDS是什么三、FastDDS的源码编译四、FastDDS的简单测试 一、Ubuntu系统介绍 Ubuntu是一个基于Linux的开源操作系统&#xff0c;由Canonical公司开发和维护。它以其易用性、稳定性和安全性而受到广泛赞誉。Ubuntu系统提供了一个图形化的桌面环境…

深入解析链表:解锁数据结构核心奥秘

一. 链表的定义 链表是一种线性数据结构&#xff0c;由一系列节点组成。每个节点包含两个部分&#xff1a; 数据域&#xff08;Data&#xff09;&#xff1a;存储节点的数据。指针域&#xff08;Pointer&#xff09;&#xff1a;存储指向下一个节点的地址。 链表的第一个节点…

微信小程序开发_准备工作

1 注册小程序 注册地址 https://mp.weixin.qq.com/wxopen/waregister?actionstep1&sourcempregister&token&langzh_CN 2 完善小程序信息 进入微信公众平台https://mp.weixin.qq.com/,登录账号 登录后,在首页完善小程序信息和小程序类目 完成后在左侧找到开发…

权威认可 | Smartbi连续5年入选“Gartner增强数据分析代表厂商”

近日&#xff0c;全球权威技术研究与咨询公司Gartner最新发布《2024 年中国数据、分析和人工智能技术成熟度曲线》&#xff0c;Smartbi以其卓越的增强数据分析及自助分析能力&#xff0c;再次入选代表厂商&#xff0c;这也是Smartbi连续5年入选增强数据分析及自助分析代表厂商&…

优选算法2

五、位运算 常见位运算总结 &&#xff1a;有0就是0&#xff1b; |&#xff1a;有1就是1 ^&#xff1a;相同为0&#xff0c;相异就是1/无进位相加 给定一个数n,确定它的二进制表示中的第x位是0还是1&#xff1a;二进制中权值最小的是第0位&#xff0c;所以int整型是从第0位到…

os实训课程模拟考试(选择题复习)

目录 一、操作系统的基本功能和设计目标 &#xff08;1&#xff09;基础知识 &#xff08;2&#xff09;题目与答案 1、操作系统是一组 B &#xff08;单选&#xff09; 2、以下哪项不是操作系统关心的主要问题&#xff1f;D &#xff08;单选&#xff09; 3、下列关于…

基于Ansys workbench进行发动机风扇非定常流固耦合计算

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&…

MFC扩展库BCGControlBar Pro v35.0新版亮点 - 工具栏、菜单全新升级

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v35.0已全新发布了&#xff0c;这个版本改进类Visual Studio 2022的视觉主题、增强对多个…

pytest中的极其重要固件(request)的理解

pytest 是一个非常流行的Python测试框架&#xff0c;它为开发人员提供了丰寴的测试工具和功能。 在pytest中&#xff0c;固件&#xff08;fixture&#xff09;是一种非常核心的概念&#xff0c;用于设置测试前的预条件&#xff0c;清理测试后的环境&#xff0c;或者提供测试过…

vxeTable反转表格

文章目录 前言 前言 如果遇到列为动态值&#xff0c;行相对固定的情况&#xff0c;这种时候就需要用到行列反转&#xff0c;这里我以vxeTable表格为例。 直接上代码 <vxe-gridref"tableRefRight":auto-resize"true":columns"dataColumn":dat…

springboot中使用springboot cache

前言&#xff1a;SpringBoot中使用Cache缓存可以提高对缓存的开发效率 此图片是SpringBootCache常用注解 Springboot Cache中常用注解 第一步&#xff1a;引入依赖 <!--缓存--><dependency><groupId>org.springframework.boot</groupId><artifactId…

【ai】trition:tritonclient yolov4:ubuntu18.04部署python client成功

X:\05_trition_yolov4_clients\01-python server代码在115上,client本想在windows上, 【ai】trition:tritonclient.utils.shared_memory 仅支持linux 看起来要分离。 【ai】tx2 nx:ubuntu18.04 yolov4-triton-tensorrt 成功部署server 运行 client代码远程部署在ubuntu18.0…

分布式锁及其实现与应用场景

分布式锁及其实现与应用场景 分布式锁是一种用于在分布式系统中协调多个进程或线程对共享资源进行访问的机制。它的主要目的是确保在同一时间只有一个进程或线程可以访问特定资源&#xff0c;从而避免数据竞争和不一致问题。分布式锁通常用于集群环境中&#xff0c;例如微服务…

二次封装 el-dialog 实现 全屏和最小化 功能

效果 封装后的组件 <template><el-dialog v-model"dialogVisible" :show-close"false" :fullscreen"fullscreen" draggable overflow><template #header"{ close }"><div><span style"font-weight: b…

Python operator模块这么用,效率杠杠的!

目录 1、基础操作符应用 🐍 1.1 加载operator模块 1.2 使用itemgetter进行排序 1.3 attrgetter与方法调用 2、高级功能探索 🔍 2.1 methodcaller的妙用 2.2 操作符重载与定制 3、结合lambda表达式 ✨ 3.1 lambda与operator模块协同工作 3.2 实战案例分析 4、结合…