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

目录

一、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)




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


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




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


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

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

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

相关文章

Activiti7官方在线流程设计器下载和部署

文章目录 一、流程设计器下载二、流程设计器简单运行三、流程设计器简单使用四、流程设计器持久化持久化会遇到的常见错误 五、流程设计器汉化说明菜单汉化操作汉化 参考文档 一、流程设计器下载 官网下载地址&#xff1a;https://www.activiti.org/get-started 点击直接获取官…

Flutter 小技巧之升级适配 Xcode15

美好的 2024 从「适配」开始&#xff0c;按照苹果的尿性&#xff0c;2024 春季开始大家将不得使用 Xcode15 来构建 App &#xff0c;另外根据《2024 的 iOS 的隐私清单》 要求&#xff0c;使用 Flutter 的开发者是无法逃避适配 Xcode15 更新的命运。 另外&#xff0c;众所周知…

vue3组件传参

1、props: 2、自定义事件子传父 3、mitt任意组件通讯 4、v-model通讯(v-model绑定在组件上) (1)V2中父子组件的v-model通信&#xff0c;限制了popos接收的属性名必须为value和emit触发的事件名必须为input,所以有时会有冲突; 父组件: 子组件: (2)V3中:限制了popos接收的属性名…

详解Java死锁-检测与解决

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff0c;咱们今天来聊聊死锁。特别是对于咱们这些Java程序员来说&#xff0c;死锁就像是隐藏在暗处的陷阱&#xff0c;稍不注意就会掉进去。但别担心&#xff0c;小黑今天就来带大家一探究竟&#xff0c;看看怎么样才能避…

什么是短视频矩阵系统?效果是怎么样的?

短视频矩阵系统是一种通过将多个短视频连接起来形成一个整体的系统。它的效果是可以提供一种连贯而有序的观看体验&#xff0c;使观众可以连续地观看一系列相关的短视频内容。 短视频矩阵系统的运作方式如下&#xff1a;首先&#xff0c;用户在平台上选择一个短视频开始观看。…

一款开源的MES系统

随着工业4.0的快速发展&#xff0c;制造执行系统&#xff08;MES&#xff09;成为了智能制造的核心。今天&#xff0c;将为大家推荐一款开源的MES系统——iMES工厂管家。 什么是iMES工厂管家 iMES工厂管家是一款专为中小型制造企业打造的开源MES系统。它具备高度的可定制性和灵…

刷了四百道算法题,我在项目里用过哪几道呢?

大家好&#xff0c;我是老三&#xff0c;今天和大家聊一个话题&#xff1a;项目中用到的力扣算法。 不知道从什么时候起&#xff0c;算法已经成为了互联网面试的标配&#xff0c;在十年前&#xff0c;哪怕如日中天的百度&#xff0c;面试也最多考个冒泡排序。后来&#xff0c;…

强化学习的数学原理学习笔记 - 策略梯度(Policy Gradient)

文章目录 概览&#xff1a;RL方法分类策略梯度&#xff08;Policy Gradient&#xff09;Basic Policy Gradient目标函数1&#xff1a;平均状态值目标函数2&#xff1a;平均单步奖励&#x1f7e1;PG梯度计算 &#x1f7e6;REINFORCE 本系列文章介绍强化学习基础知识与经典算法原…

android的求职APP 前端+后端

一 项目名称 基于android的求职APP&#xff0c;包含前台和后台管理系统的&#xff0c;前端主要移动端&#xff0c;应聘者注册账号&#xff0c;然后登陆&#xff0c;完善自己的简历&#xff0c;然后根据自己的需要投递岗位&#xff0c;查看面试邀请&#xff0c;后台主要维护数据…

听GPT 讲Rust源代码--compiler(34)

File: rust/compiler/rustc_middle/src/ty/print/mod.rs 在Rust源代码中&#xff0c;文件rust/compiler/rustc_middle/src/ty/print/mod.rs的作用是定义了打印类型和其他相关信息的功能。 具体来说&#xff0c;该文件中定义了三个trait&#xff0c;分别为Print<tcx>、Pri…

Java_特殊文件

一、属性文件 1.1 特殊文件概述 前面学习了IO流&#xff0c;知道IO流是用来读、写文件中的数据。但是接触到的文件都是普通的文本文件&#xff0c;普通的文本文件里面的数据是没有任何格式规范的&#xff0c;用户可以随意编写&#xff0c;如下图所示。 像这种普通的文本文件…

Selenium教程08:文件的上传+下载的示例练习

1.上传李白.txt文件&#xff0c;这里使用的send_keys方法操作&#xff0c;而不是click点击操作&#xff0c;因为使用点击操作之后&#xff0c;Selenium中没有方法对.exe程序操作&#xff0c;它只能对web网页自动化操作。 # Author : 小红牛 # 微信公众号&#xff1a;WdPython…

web前端开发技术复习问答题

目录 1.简述常见单标签和双标签有哪些&#xff1f; 2.常见块级元素和行级元素有哪些&#xff1f; 3.简述常见的列表有哪些&#xff1f;他们有什么区别&#xff1f; 4.简述超链接的href属性值如何设置&#xff1f;有什么区别 5.CSS基本语法 6. css中常见的引入方式有几种&…

AIGC-无人直播系统技术源头

AIGC-无人直播系统技术&#xff0c;作为当今科技领域的一项重要创新&#xff0c;正在引领着直播行业迈向更高的境界。那么&#xff0c;究竟是什么推动了这项技术的发展呢&#xff1f; 首先&#xff0c;我们不得不提到人工智能&#xff08;AI&#xff09;这一前沿技术的发展。随…

【数据库】CRUD常用函数UNION 和 UNION ALL

文章目录 一、CRUD二、函数2.1 字符函数 (Character Functions):2.2 数字函数 (Numeric Functions):2.3 日期函数 (Date Functions):2.4 流程控制函数:2.5 聚合函数: 三、UNION 和 UNION ALL3.1 UNION&#xff1a;3.2 UNION ALL3.3 注意事项 一、CRUD CRUD 是指数据库操作的四…

Qt/QML编程学习之心得:QProcess进程创建(27)

Qt除了线程Thread,进程也有支持类,那就是QProcess。 可以看出,这个类很大,支持的内容也很多。最简单的使用如: myParam << QString("-param hello") ; bool bRes = QProcess::startDetached("/usr/bin/myApplication", myParam);要启动进程,主…

Vue-4、单向数据绑定与双向数据绑定

1、单向数据绑定 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>数据绑定</title><!--引入vue--><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/…

机器学习(四) -- 模型评估(2)

系列文章目录 机器学习&#xff08;一&#xff09; -- 概述 机器学习&#xff08;二&#xff09; -- 数据预处理&#xff08;1-3&#xff09; 机器学习&#xff08;三&#xff09; -- 特征工程&#xff08;1-2&#xff09; 机器学习&#xff08;四&#xff09; -- 模型评估…

springboot 物业管理系统

springboot mysql mybatisthymeleaf 基础信息管理 房屋信息 用户信息 业主信息 租房信息 公告管理 日常管理 财务管理

Linux环境vscode clang-format格式化:vscode clang format command is not available

问题现象 vscode安装了clang-format插件&#xff0c;但是使用就报错 问题原因 设置中配置的clang-format插件工具路径不正确。 解决方案 确认本地安装了clang-format工具&#xff1a;终端输入clang-format&#xff08;也可能是clang-format-13等版本&#xff0c;建议tab自…