【c++】list的特性及使用

news2024/12/24 11:37:23

目录

一、list的介绍

二、list的深度剖析与模拟实现

1、list图解

2、list增删查改模拟实现

三、list与vector的对比


一、list的介绍

        STL中的list指的是带头双向循环链表。list是可以在常数范围内任意位置进行插入和删除的序列式容器,并且可以前后双向迭代。list中每个元素的存储相互独立,通过每个节点中的指针指向其前一个元素和后一个元素。list因为每个节点的存储位置相互独立而是的插入和删除元素不需要移动其他元素让其效率更高,但是list也因此不能支持任意位置的随机访问,不能随机访问是它最大的缺陷。

二、list的深度剖析与模拟实现

1、list图解

        list的节点中有三个成员变量(哨兵位头节点除外),分别是:有效数据date、指向下一个节点的指针变量next、指向前一个节点的指针变量pre,哨兵位头节点不存储有效数据,只有两个指针变量。

2、list增删查改模拟实现

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


namespace lbj
{
    // List的节点类
    template<class T>
    struct ListNode
    {
        ListNode(const T& val = T())
            :_val(val)
            ,_pPre(nullptr)
            ,_pNext(nullptr)
        {}
        ListNode<T>* _pPre;
        ListNode<T>* _pNext;
        T _val;
    };

    //List的迭代器类
    template<class T, class Ref, class Ptr> //Ref是T类型的引用;Ptr是指向T类型数据的指针
    class ListIterator
    {
        typedef ListNode<T> Node;
        typedef ListNode<T>* PNode;
        typedef ListIterator<T, Ref, Ptr> Self;
    public:
        
        ListIterator(PNode pNode = nullptr)
            :_pNode(pNode)
        {}
        ListIterator(const Self& l);
        Ref operator*()
        {
            return _pNode->_val;
        }
        Ptr 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);
        }
    private:
        PNode _pNode;
    };

    //list类
    template<class T>
    class list
    {
        typedef ListNode<T> Node;
        typedef ListNode<T>* PNode;
        typedef ListIterator<T, T&, T*> iterator;
        typedef ListIterator<T, const T&, const T*> const_iterator;
    public:

        // List Iterator
        iterator begin()
        {
            return _pHead->_pNext;
        }
        iterator end()
        {
            return _pHead;
        }
        const_iterator begin() const
        {
            return _pHead->_pNext;
        }
        const_iterator end() const
        {
            return _pHead;
        }


        // List Capacity
        size_t size()const;
        bool empty()const;


        // List Access
        T& front();
        const T& front()const;
        T& back();
        const T& back()const;


        // List Modify
        iterator insert(iterator pos, const T& val)// 在pos位置前插入值为val的节点,返回新插入元素的迭代器
        {
            PNode cur = pos._pNode;
            PNode pre = cur->_pPre;
            PNode NewNode = new Node(val);
            pre->_pNext = NewNode;
            NewNode->_pPre = pre;
            NewNode->_pNext = cur;
            cur->_pPre = NewNode;
            return iterator(NewNode);   //返回新插入元素的迭代器
        }
        iterator erase(iterator pos)// 删除pos位置的节点,返回该节点的下一个位置
        {
            PNode cur = pos;
            PNode pre = cur->_pPre;
            PNode next = cur->_pNext;
            pre->_pNext = next;
            next->_pPre = pre;
            delete cur;
            return iterator(next);  //返回该节点的下一个位置
        }
        void push_back(const T& val)    //{ insert(end(), val); }
        {
            //insert(end(), val);
            PNode tail = _pHead->_pPre;
            PNode NewNode = new Node(val);
            tail->_pNext = NewNode;
            NewNode->_pPre = tail;
            NewNode->_pNext = _pHead;
            _pHead->_pPre = NewNode;
        }
        void pop_back() 
        {
            erase(--end()); 
        }
        void push_front(const T& val) 
        { 
            insert(begin(), val); 
        }
        void pop_front() 
        { 
            erase(begin()); 
        }
        void clear()
        {
            iterator it = begin();
            while (it != end())
            {
                it = erase(it);
            }
        }
        void swap(list<T>& l)
        {
            std::swap(_pHead, l._pHead);
        }

        // List的构造
        void empty_init()
        {
            _pHead = new Node;
            _pHead->_pPre = _pHead;
            _pHead->_pNext = _pHead;
        }
        list()
        {
            empty_init();
        }
        list(int n, const T& value = T());
        template <class Iterator>
        list(Iterator first, Iterator last);
        list(const list<T>& l)
        {
            empty_init();
            for (auto L_N : l)
            {
                push_back(L_N);
            }
        }
        list<T>& operator=(const list<T> l)
        {
            //if (this != &l)
            //{
            //    clear();
            //    for (auto L_N : l)
            //    {
            //        push_back(L_N);
            //    }
            //}

            swap(l);
            return *this;
        }
        ~list()
        {
            clear();
            delete _pHead;
            _pHead = nullptr;
        } 
    private:
        void CreateHead();
        PNode _pHead;
    };
};

三、list与vector的对比

vectorlist



动态顺序表,一段连续空间带头结点的双向循环链表


访
支持随机访问,访问某个元素的效率是O(1)   不支持随机访问,访问某个元素的效率是O(n)




除 
   任意位置插入和删除效率低,需要移动部分元素,时间复杂度是O(n),插入元素可能需要扩容,开辟新空间、拷贝元素、释放旧空间,这些操作导致效率低下   任意位置插入和删除效率高,不需要
移动其他元素,时间复杂度是O(1)




   底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高   底层节点是动态开辟出来的,小节点容易造成内存碎片,空间利用率低,缓存利用率低


原生态指针被封装的原生态指针(节点指针)




   在插入元素时,要给所有迭代器重新赋值,因为插入元素有可能导致扩容,使得原来迭代器失效,删除时,当前迭代器也需要重新赋值   插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
使


   需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AI视野·今日CV 计算机视觉论文速览 第283期】Thu, 4 Jan 2024

AI视野今日CS.CV 计算机视觉论文速览 Thu, 4 Jan 2024 Totally 85 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers LEAP-VO: Long-term Effective Any Point Tracking for Visual Odometry Authors Weirong Chen, Le Chen, Rui Wang, Marc P…

大数据可视化Web框架——飞致云Dataease在Windows端的安装指南(多图说明版)V2.2最新版

DataEase开源代码在Windows系统开发环境搭建与调试指南_怎么部署dataease 2.0-CSDN博客https://blog.csdn.net/tllhc01/article/details/135220598?spm1001.2014.3001.5502参考这一篇&#xff0c;基于dataease2.2源码进行构建 需要先下载三个文件&#xff0c;且版本一一对应均…

性能分析与调优: Linux 监测工具的数据来源

目录 一、实验 1.环境 2. proc目录 3. sys目录 4.netlink 5.tracepoint 6.kprobes 7. uprobes 二、问题 1.systemd如何查看启动时间 2.CentOS与Ubuntu如何安装bpftrace 3.snap有哪些常用的命令 4.snap如何安装store 5.如何列出使用bpftracede的OpenJDK USDT探针 …

机器学习笔记:时间序列异常检测

1 异常类型 1.1 异常值outlier 给定输入时间序列&#xff0c;异常值是时间戳值其中观测值与该时间序列的期望值不同。 1.2 波动点&#xff08;Change Point&#xff09; 给定输入时间序列&#xff0c;波动点是指在某个时间t&#xff0c;其状态在这个时间序列上表现出与t前后…

基于JSP+Servlet+Mysql的学生信息管理系统

基于JSPServletMysql的学生信息管理系统 一、系统介绍二、功能展示1.目录2.数据库3.登陆4.注册5.主页 四、其它1.其他系统实现五.获取源码 一、系统介绍 项目名称&#xff1a;基于JSPServletMysql的学生信息管理系统 项目架构&#xff1a;B/S架构 开发语言&#xff1a;Java语…

Web前端-JavaScript(BOM)

文章目录 1.1 常用的键盘事件1.1.1 键盘事件1.1.2 键盘事件对象1.1.3 案例一 1.2 BOM1.2.1 什么是BOM1.2.2 BOM的构成1.2.3 window1.2.4 window对象常见事件窗口/页面加载事件**第1种****第2种** 调整窗口大小事件 1.2.5 定时器setTimeout() 炸弹定时器停止定时器**案例&#x…

python 写自动点击爬取数据

今天来点不一样的&#xff01;哥们 提示&#xff1a; 这里只是用于自己学习的 &#xff0c;请勿用违法地方 效果图 会进行点击下一页 进行抓取 需要其他操作也可以自己写 文章目录 今天来点不一样的&#xff01;哥们前言一、上代码&#xff1f;总结 前言 爬虫是指通过编程自动…

Spring Framework和SpringBoot的区别

目录 一、前言 二、什么是Spring 三、什么是Spring Framework 四、什么是SpringBoot 五、使用Spring Framework构建工程 六、使用SpringBoot构建工程 七、总结 一、前言 作为Java程序员&#xff0c;我们都听说过Spring&#xff0c;也都使用过Spring的相关产品&#xff0…

基因组学之碱基突变的关键概念

碱基突变 突变&#xff08;muation&#xff09;会引起DNA序列的变化&#xff0c;进一步会引起蛋白序列的改变。正常的细胞活动或细胞与环境的随机相互作用&#xff0c;会使得生物产生一定数目的突变&#xff0c;称为自发突变&#xff08;spontaneous muation&#xff09;。突变…

多线程第一课---

UML中规定的箭头方向是从子类指向父类。 关于这一点&#xff0c;按照以下方法去理解有助于大家记住这条规则。 在定义子类时需要通过extends关键字指定父类。因此&#xff0c; 子类一定要知道父类的定义&#xff0c;而反过来&#xff0c;父类并不知道子类的定义。 只有在知道对…

Spring事务(2):声明式事务管理案例-转账(xml、注解)

1 编写转账案例&#xff0c;引出事务管理问题 需求&#xff1a;账号转账&#xff0c;Tom账号取出1000元&#xff0c;存放到Jack账号上 1.1 建表脚本&#xff08;MySQL&#xff09; CREATE TABLE t_account (id INT(11) NOT NULL AUTO_INCREMENT,name VARCHAR(20) NOT NULL,m…

Arduino开发实例-欧姆龙E3Z-D61光电传感器

欧姆龙E3Z-D61光电传感器 文章目录 欧姆龙E3Z-D61光电传感器1、E3Z-D61光电传感器介绍2、硬件准备及接线3、代码实现1、E3Z-D61光电传感器介绍 Omran 光电传感器可用于检测 5 至 100 毫米距离内的障碍物和物体。 传感器上有一个 LED,它始终熄灭,并在检测到障碍物时亮起。 您…

Plantuml之nwdiag网络图语法介绍(二十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

IDEA[Debug]简单说明

目录 &#x1f95e;1.打断点 &#x1f32d;2.第一组按钮 &#x1f9c2;3.第二组按钮 &#x1f953;4.参数查看 1.打断点 1.在需要断点处打上断点&#xff0c;然后点击debug运行 2.执行debug&#xff0c;直接执行到断点处 2.第一组按钮 共有8按钮&#xff0c;从左往右依…

【普中开发板】基于51单片机的简易密码锁设计( proteus仿真+程序+设计报告+讲解视频)

基于51单片机的简易密码锁设计 1.主要功能&#xff1a;资料下载链接&#xff1a; 实物图&#xff1a;2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单 【普中】基于51单片机的简易密码锁设计 ( proteus仿真程序设计报告讲解视频&#xff09; 仿真图proteus8.16(有低版本) 程…

Defi安全-Monox攻击事件Foundry复现

其它相关内容可见个人主页 Mono攻击事件的介绍见&#xff1a;Defi安全–Monox攻击事件分析–phalconetherscan 1. 前情提要和思路介绍 Monox使用单边池模型&#xff0c;创建的是代币-vCash交易对&#xff0c;添加流动性时&#xff0c;只需添加代币&#xff0c;即可进行任意代…

秋招复习之堆

目录 前言 堆 堆的常用操作 堆的实现&#xff08;大根堆&#xff09; 1. 堆的存储与表示 2. 访问堆顶元素 3. 元素入堆 4. 堆顶元素出堆 Top-k 问题 方法一&#xff1a;遍历选择 方法二&#xff1a;排序 方法三&#xff1a;堆 总结 前言 秋招复习之堆。 堆 「堆 heap…

分布式系统——广播Broadcasts

1 广播抽象(Broadcast Abstractions)在进程中的两种方法 在分布式系统中广播抽象的概念。广播抽象允许系统中的进程使用两种基本方法进行通信&#xff1a; 1.1 Broadcast(m) 当一个进程 i 使用这个方法时&#xff0c;它会将消息 m 发送给系统中的所有其它进程。 1.2 …

数据结构实验1:栈和队列的应用

目录 一、实验目的 二、实验原理 1.1栈的基本操作 1.1.1 栈的定义 1.1.2 初始化栈 1.1.3 压栈&#xff08;Push&#xff09; 1.1.4 出栈&#xff08;Pop&#xff09; 1.1.5 判空&#xff08;isEmpty&#xff09; 1.1.6 查看栈顶元素&#xff08;Top&#xff09; 1.1…

【好书推荐】我的第一本科技漫画书:漫画区块链

王杰&#xff0c;南京理工大学物理电子学硕士&#xff0c;曾担任乐视VR技术总监&#xff0c;现为北京米唐科技有限公司CEO&#xff0c;知乎“区块链”领域知名作者&#xff0c;北京信息科技大学、北京建筑大学、北京信息职业技术学院客座教授。 郑巍&#xff0c;擅长绘制钢笔淡…