C++学习指南(六)----list

        欢迎来到繁星的CSDN。本期内容主要包括,list的介绍、使用以及与vector的优缺点。        

一、什么是list

        在先前的C语言学习中,我们接触到了顺序表和链表,而在C++中,这正好对应了vector(动态增长顺序表)和list(链表)。所以本期的内容实质上仍然是与链表相关的封装、重载函数等。

           list和之前说的string、vector一样,属于container(容器),作为STL库里的常客,list的出场为我们的链表提供的简易的使用方法。但是很可惜的是,我们的二叉树等链表的变形却不能直接使用。原因是list实质上是带头双向链表。(HEAD节点和其余节点结构一致,但是在list内为空时,该节点不销毁,只是为空)

二、list的接口

        list的接口比之list而言更有序,但数量仍然十分众多。

        具体查看网址如下:

        cplusplus.com/reference/list/list/

      构造constructor

explicit list ();//默认构造explicit list (size_type n);//传值构造
list (size_type n, const value_type& val);//传值构造template <class InputIterator>  list (InputIterator first, InputIterator last);//区间构造list (const list& x);//拷贝构造

   文档中还有其他重载函数,以及以上展示的构造函数中,我已将有关空间配置器的内容省去(因为大部分情况下我们只需要使用STL原生的配置器就可以了)。

   实际上我们可以发现,list的构造函数和vector的构造函数差别不大。

      销毁destructor

~list();

    和我们熟悉的销毁方式没有什么区别。实际上就是将链表中的动态申请部分释放,并将相关成员变量置空。而且由于这是STL库内的部分而非自定义类型需要我们自己实现,当程序结束的时候,将会自动调用销毁函数,所以无需担心。

       赋值重载operator=

list& operator= (const list& x);

     

   经过实践检验得知,当我们使用=赋值另一个list的时候,两者的地址不同,所以这是深拷贝,无需担心先前的list销毁导致复制出来的list同时销毁。 

      迭代器iterator

        list的迭代器我们可以暂时理解为指针。

#include<iostream>
#include<list>
using namespace std;int main() {int array[] = { 1,2,3,4,0,5,6,7,8,9 };int n = sizeof(array) / sizeof(int);list<int> mylist(array, array + n);auto it = mylist.begin();*it = 0;for (int a : mylist) {cout << a << endl;}return 0;
}

        (这里偷偷使用了auto来偷懒,实际写可以写为list::iterator)

        之前提过,迭代器的出现就是为了封装,减少记忆成本。

        所以这里的it仍然可以实现,++,--,*这几个方式。

        ++就是到下一个节点,--就是返回上一个节点,*就是解引用。

        与迭代器相关的接口如下:
        

   begin(),end()                          //正向迭代器

   rbegin(),rend()                       //反向迭代器

   cbegin(),cend()                      //const正向迭代器

   crbegin(),crend()                   //const反向迭代器

        但是有一点比较麻烦,list不再支持[ ],也就是随机访问。

        原因在于,底层的链表实现随机访问的代价太大,即使list的底层是带头双向链表,由于物理储存空间的不连续性,最坏情况也可以达到O(n/2)。

      容器大小capacity

    empty();

    size();

    max_size();

        相比vector,list的capacity变成了max_size,这是因为链表某一结点的空间都是单独申请,所以不存在可容纳空间这一概念,取代capacity的是max_size,代表可供使用的空间大小,这取决于系统,而非自己申请。

      访问方式access

   front();

   back();

        front与back分别是整个list的头与尾,可以通过这两个直接得到。

      成员函数member function

void push_front (const value_type& val);
void push_back (const value_type& val);
void pop_front();
void pop_back();
//对单个元素进行操作iterator erase (const_iterator position);//删除单个元素
iterator erase (const_iterator first, const_iterator last);//删除区间内的元素iterator insert (const_iterator position, const value_type& val);
iterator insert (const_iterator position, size_type n, const value_type& val);
//在某一位置插入一个或多个同一元素
template <class InputIterator>
iterator insert (const_iterator position, InputIterator first, InputIterator last);
//在某一位置插入另一容器的部分元素

       对list的相关函数操作,实际上和vector差别不大,当然C++11还支持了emplace_back,emplace_front,emplace,这分别对应push_back,push_front,insert。不过对于左值引用而言,效率一样,对于右值引用(这里未书写,仅仅是将参数类型变成右值),emplace的效率更高。

        当然list的相关函数还有很多,感兴趣的可以看:

        cplusplus.com/reference/list/list/

三、list和vector的优劣与不可替代性

        说起list,就不能不提到与vector的优劣势,以及是否可以被替代。

        list和vector的优劣取决于他们的储存方式。vector是由一段连续的物理空间储存,而list是不必使用连续空间储存,却不支持随机访问。

vectorlist
底层结构动态顺序表、连续物理空间带头双向链表
随机访问支持不支持
插入与删除尾端效率高,其余位置需要挪动元素,效率不高任意位置效率均高,O(1)
空间利用率空间利用率高、缓存利用率高空间利用率低、缓存利用率低
迭代器原生指针对原生指针进行封装
迭代器失效插入时如发生扩容,迭代器失效,删除时当前迭代器失效插入不会导致失效,删除时仅当前迭代器失效
使用场景需要高效储存、需要随机访问,不需要大量插入删除操作大量插入删除操作

四、list的模拟实现

namespace show
{// List的节点类template<class T>struct ListNode{T _val;ListNode<T>* _pPre;ListNode<T>* _pNext;ListNode(const T& val = T()):_val(val),_pNext(nullptr),_pNext(nullptr){};};//List的迭代器类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*(){return _node->_data;}Ptr operator->(){return &_node->_data;}Self& operator++(){_node = _node->_next;return *this;}Self& operator--(){_node = _node->_prev;return *this;}Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}Self& operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}};//list类template<class T>class list{typedef list_node<T> Node;public:typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;iterator begin(){return _head->_next;}iterator end(){return _head;}const_iterator begin() const{return _head->_next;}const_iterator end() const{return _head;}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}list(){empty_init();}list(initializer_list<T> il){empty_init();for (auto& e : il){push_back(e);}}list(const list<T>& lt){empty_init();for (auto& e : lt){push_back(e);}}list<T>& operator=(list<T> lt){swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){auto it = begin();while (it != end()){it = erase(it);}}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;prev->_next = newnode;++_size;return newnode;}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator erase(iterator pos){assert(pos != end());Node* prev = pos._node->_prev;Node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;--_size;return next;}size_t size() const{return _size;}bool empty() const{return _size == 0;}private:Node* _head;size_t _size;};
};

        

        本篇内容到此结束,谢谢大家的观看!

        觉得写的还不错的可以点点关注,收藏和赞,一键三连。

        我们下期再见~

        往期栏目:

        C++学习指南(一)——C++入门基础_c++ 学习指南-CSDN博客

        C++学习指南(二)——类和对象-CSDN博客

        C++学习指南(三)——模板_模板类-CSDN博客

        C++学习指南(四)------string-CSDN博客

        C++学习指南(五)——vector_erwei vector bianliangchushihua-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux第三课(linux中安装nginx与redis及SpringBoot集成redis)

目录 一.nginx引入 二.关于nginx 1.什么是nginx 2.nginx的特点 3.在nginx中安装nginx 三.关于redis 1.背景引入 2.什么是redis 3.redis的特点 4.在linux下的docker中安装redis 四.redis中的数据结构 (1)String(字符串) (2)Hash (3)list(列表) (5)zset(sorted se…

Python模拟鼠标轨迹[Python]

一.鼠标轨迹模拟简介 传统的鼠标轨迹模拟依赖于简单的数学模型&#xff0c;如直线或曲线路径。然而&#xff0c;这种方法难以捕捉到人类操作的复杂性和多样性。AI大模型的出现&#xff0c;能够通过深度学习技术&#xff0c;学习并模拟更自然的鼠标移动行为。 二.鼠标轨迹算法实…

博睿谷IT认证-订阅试学习

在这个信息爆炸的时代&#xff0c;拥有一张IT认证证书&#xff0c;就像拿到了职场晋升的通行证。博睿谷&#xff0c;作为IT认证培训的佼佼者&#xff0c;帮你轻松拿下华为、Oracle等热门认证。下面&#xff0c;让我们一起看看博睿谷如何助你一臂之力。 学习时间&#xff0c;你说…

C++入门基础知识82(实例)——实例7【 判断一个数是奇数还是偶数】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C 实例 【判断一个数是奇数还是偶数】相…

java重点学习-总结

十五 总结 https://kdocs.cn/l/crbMWc8xEZda &#xff08;总结全部的精华&#xff09; 1.面试准备 企业筛选简历规则简历编写注意事项(亮点)项目怎么找&#xff0c;学习到什么程度面试过程(表达结构、什么样的心态去找工作) 2.redis 缓存相关(缓存击穿、穿透、雪崩、缓存过期淘…

传输层协议 —— TCP协议(上篇)

目录 1.认识TCP 2.TCP协议段格式 3.可靠性保证的机制 确认应答机制 超时重传机制 连接管理机制 三次握手 四次挥手 1.认识TCP 在网络通信模型中&#xff0c;传输层有两个经典的协议&#xff0c;分别是UDP协议和TCP协议。其中TCP协议全称为传输控制协议&#xff08;Tra…

远程升级频频失败?你可能忽略了模组差分包…

去年开发的一个项目产品&#xff0c;用的是合宙4G-Cat.1低功耗模块Air780E。 最近有客户反馈在乡村里频繁出现掉线的情况。通过换货、换SIM卡对比排查测试&#xff0c;发现只有去年5月22号采购的那批模块在客户环境附近会出现掉线的情况&#xff0c;而今年4月份采购的模块批次…

【Go】Go 环境下载与安装教程(Windows系统)

引言 Go&#xff0c;也被称为Golang&#xff0c;是一种静态类型&#xff0c;编译型的编程语言&#xff0c;由Google设计和开发。Go语言的设计目标是“解决软件开发中的一些问题”&#xff0c;特别是在大规模软件系统的构建和维护方面。 下载安装包 打开官网下载页面&#xff…

03 添加并发请求

03 添加并发请求 我们通过两种方式演示发起多个请求&#xff1a; 使用 async 和 await 方式使用 Promise.all() 方式 首先使用async 和 await 方式发送请求&#xff0c;使用 async 和 await 能够控制异步任务以同步的流程执行&#xff0c;代码如下&#xff0c;这时候就会产生…

Git 提交规范

一、Git 提交规范的基本格式 通常&#xff0c;Git 提交信息采用以下格式&#xff1a; <type>: <subject><body><footer>type&#xff08;提交类型&#xff09;&#xff1a;用于说明提交的性质&#xff0c;常见的类型有以下几种&#xff1a; feat&…

仓颉编程语言4,遇到BUG求助

本来准备整仓颉链接Mysql数据库。参考&#xff1a;GitCode - 全球开发者的开源社区,开源代码托管平台 这种方式是拿mysql官方的dll&#xff0c;编译一下&#xff0c;然后再封装成仓颉数据库驱动。这种方式不够逼格&#xff0c;所以准备解析mysql网络协议&#xff0c;从0开始写…

cmd快速进入文件夹目录下

首先&#xff0c;将文件夹直接点击左键拖动至cmd窗口中&#xff0c;就可以得到目录路径。 还有就是&#xff0c;在命令行直接敲入D:或者C:就可以在磁盘之间进行转换&#xff0c;注意冒号不要丢。 再有&#xff0c;如果进入某磁盘中的一个文件夹&#xff0c;使用cd命令。路径获取…

SpringBoot实战(三十)发送HTTP/HTTPS请求的五种实现方式【下篇】(Okhttp3、RestTemplate、Hutool)

目录 一、五种实现方式对比结果二、Demo接口地址实现方式三、Okhttp3 库实现3.1 简介3.2 Maven依赖3.3 配置文件3.4 配置类3.5 工具类3.6 示例代码3.7 执行结果实现方式四、Spring 的 RestTemplate 实现4.1 简介4.2 Maven依赖4.3 配置文件4.4 配置类4.5 HttpClient 和 RestTemp…

Parallels Desktop 20 for Mac 推出:完美兼容 macOS Sequoia 与 Win11 24H2

Parallels Desktop 20 for Mac 近日正式发布&#xff0c;这一新版本不仅全面支持 macOS Sequoia 和 Windows 11 24H2&#xff0c;还在企业版中引入了一个全新的管理门户。新版本针对 Windows、macOS 和 Linux 虚拟机进行了多项改进&#xff0c;其中最引人注目的当属 Parallels …

导出导入Oracle数据库使用黑框命令方式exp、imp【亲测】

下载工具 根据自己数据库的版本下载&#xff0c;以v19为例&#xff1a; 下载基础包Basic Package和工具包Tools Package 两个压缩包中的文件夹一样&#xff0c;但内容不一样&#xff0c;将两个压缩包中的文件解压合并到一起 https://www.oracle.com/database/technologies/inst…

SpringCloud入门(六)Nacos注册中心(下)

一、Nacos环境隔离 Nacos提供了namespace来实现环境隔离功能。 nacos中可以有多个namespace。namespace下可以有group、service等。不同namespace之间相互隔离&#xff0c;例如不同namespace的服务互相不可见。 使用Nacos Namespace 环境隔离 步骤&#xff1a; 1.在Nacos控制…

时间序列无监督异常点检测算法_孤立森林,局部离群因子检测和自编码器

数据入口&#xff1a;压气机异常检测一维时间序列 - Heywhale.com 该数据为采样自工业压气机的一维时间序列数据。本文将通过无监督时间序列算法进行时间序列异常检测。针对时间序列数据&#xff0c;常用的无监督异常检测算法包括&#xff1a;孤立森林&#xff08;Isolation Fo…

【Yonghong星球】Windows平台上Yonghong的Python、DM-Engine安装与配置详细攻略

文章目录 问题描述问题解决(配置相应的python计算服务)拓展 第三方工具包安装/更新其他出现问题 问题描述 当我们进行深度分析的时候&#xff0c;运行结点报错&#xff0c;这是因为需要配置相应的python计算服务。 报错内容&#xff1a; 2024-09-20 13:57:22 开始运行“各省G…

js中的 赋值 浅拷贝 和 深拷贝 详细解读

js数据类型主要分基本数据类型和引用数据类型。前者包括Number,String等&#xff0c;后者主要是Object,因此以下会针对不同的数据类型来分析,需要的朋友可以参考一下 基本数据类型&#xff08;Primary Data Types&#xff09;: String&#xff08;字符串&#xff09; Number&…

三端全隔离485中继器光电隔离工业级 RS485集线器2口信号放大器 抗干扰防雷

485中继器光电隔离工业级 RS485集线器2口信号放大器 抗干扰防雷https://item.taobao.com/item.htm?ftt&id713033449656 哪里信号不好&#xff0c;中继器就接哪里 将有效的对信号进行隔离放大 信号隔离 电源隔离 双向传输 即插即用 增强抗干扰 延长通信距离 产品概…