【C++】list

list

  • 1. 简单了解list
  • 2. list的常见接口
  • 3. 简单实现list
  • 4. vector和list比较


1. 简单了解list

  1. list的底层是带头双向循环列表。
  2. 因此list支持任意位置的插入和删除,且效率较高。但其缺陷也很明显,由于各节点在物理空间是不连续的,所以不支持对任意位置的访问,效率低。
  3. list的迭代器底层不仅仅是指针这么简单,因为其迭代器支持前后双向迭代,而其空间又不连续,所以其底层是对指针的封装。(后面讲)

2. list的常见接口

  1. 构造

在这里插入图片描述
例子
在这里插入图片描述

  1. 普通迭代器

在这里插入图片描述
与其他容器的迭代器一样,只不过list的底层实现更加复杂,现在暂且将其看成指针。
例子

//迭代器
void test3()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);auto it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;
}
//运行结果:
//1 2 3 4
  1. 头插头删和尾插尾删

例子

void test2()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);for (auto e : lt){cout << e << " ";}cout << endl;lt.pop_back();lt.pop_back();lt.pop_front();lt.pop_front();lt.push_front(4);lt.push_front(3);lt.push_front(2);lt.push_front(1);for (auto e : lt){cout << e << " ";}cout << endl;
}
//运行结果:
//1 2 3 4
//1 2 3 4
  1. 插入

在这里插入图片描述
例子

void test3()
{list<int> lt;lt.push_back(1);lt.push_back(3);lt.push_back(4);//想在第二个位置插入2,怎么做//lt.insert(lt.begin()+1,2);//错误的,list的iterator没有重载+。这个等下讲原因。auto it = lt.begin();++it;lt.insert(it, 2);for (auto e : lt){cout << e << " ";}cout << endl;
}
//运行结果:
//1 2 3 4

这样确定插入位置太麻烦了,可以用find查找。

auto it = find(lt.begin(),lt.end(),3);
if (it != lt.end())
{lt.insert(it,2);
}
  1. 删除

在这里插入图片描述
例子

	//删除偶数//删除后,迭代器还指向被删除空间,存在迭代器失效问题//所以要重新赋值it = lt.begin();while (it != lt.end()){if (*it % 2 == 0){it = lt.erase(it);}else{++it;}}
  1. front和back

在这里插入图片描述
例子
在这里插入图片描述

  1. 逆置和排序

在这里插入图片描述
在这里插入图片描述
例子

void test5()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.reverse();for (auto e : lt){cout << e << " ";}cout << endl;lt.sort();for (auto e : lt){cout << e << " ";}cout << endl;
}
//运行结果
//4 3 2 1
//1 2 3 4

拓展
(1)库里也有sort,为什么还要在list再写一个?C++库的sort不能用。
(2)这涉及到迭代器的分类。从功能上,由容器底层结构决定,迭代器有单项迭代器、双向迭代器和随机迭代器。单项迭代器只能++,向后迭代,例如forward_list/unordered_xxx的迭代器;双向迭代器能++/–,例如list/map/set;随机迭代器能+/-/++/–,例如string/vector/deque。
(3)有随机迭代器的容器能用随机的、双向的、单向的迭代器的库函数,有双向迭代器的容器能用双向的、单向的迭代器的库函数。
(4)list的迭代器类型是双向的,库函数sort的迭代器类型是随机的,所以list的数据排序不能用库函数sort。
在这里插入图片描述
在这里插入图片描述

  1. 归并

在这里插入图片描述
例子

void test6()
{list<int> lt1;lt1.push_back(1);lt1.push_back(3);lt1.push_back(5);lt1.push_back(7);list<int>lt2;lt2.push_back(2);lt2.push_back(4);lt2.push_back(6);lt2.push_back(8);lt1.merge(lt2);for (auto e : lt1){cout << e << " ";}cout << endl;cout << "lt1的大小为:" << lt1.size() << endl;cout << "lt2是否变为空:" << lt2.empty() << endl;
}

在这里插入图片描述

  1. unique

在这里插入图片描述
例子

	list<int> lt1;lt1.push_back(1);lt1.push_back(1);lt1.push_back(2);lt1.push_back(2);lt1.unique();cout << "lt1的大小:" << lt1.size() << endl;for (auto e : lt1){cout << e << " ";}cout << endl;

在这里插入图片描述

  1. remove

在这里插入图片描述

	list<int> lt1;lt1.push_back(1);lt1.push_back(1);lt1.push_back(2);lt1.push_back(2);lt1.remove(1);//相当于find+erasecout << "lt1的大小:" << lt1.size() << endl;for (auto e : lt1){cout << e << " ";}cout << endl;

在这里插入图片描述
remove不像erase,它的参数是值而不是迭代器,且remove如果要移除的值不存在,不会报错。

  1. splice

在这里插入图片描述

	list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);list<int> lt2;lt2.push_back(5);lt2.push_back(6);lt2.push_back(7);lt2.push_back(8);lt1.splice(lt1.begin(), lt2);//将lt2的所有节点全部转移到lt1之前lt1.splice(lt1.begin(), lt2,--lt2.end());//将lt2的最后一个元素转移到lt1之前lt1.splice(lt1.begin(), lt2, ++lt2.begin(), lt2.end());//将迭代器区间的节点转移到lt1之前lt1.splice(lt1.begin(), lt1, ++lt1.begin(), lt1.end());//将lt1第一个节点后面的节点转移到lt1之前for (auto e : lt1){cout << e << " ";}cout << endl;

3. 简单实现list

#include<iostream>
using namespace std;namespace zn
{//节点template<class T>struct ListNode{ListNode<T>* _prev;ListNode<T>* _next;T _val;ListNode(const T& val = T()):_prev(nullptr), _next(nullptr), _val(val){}};//迭代器(双向迭代器)//迭代器底层都是指针,但有些指针需要封装,例如节点的指针,不然不能满足++/--等操作template<class T, class Ref, class Ptr>//T == T, Ref == T&/const T&, Ptr == T*/const T*struct __list_iterator{typedef ListNode<T>* iterator;typedef __list_iterator<T, Ref, Ptr> This;iterator _node;//构造__list_iterator(iterator node):_node(node){}//*重载Ref operator*(){return _node->_val;}//->重载//如果T恰好是结构体类型,而迭代器又被看成指针,那么->就可以派上用场Ptr operator->(){return &(_node->_val);}//++重载This& operator++(){_node = _node->_next;return *this;}This operator++(int){This tmp(_node);_node = _node->_next;return tmp;}//--重载This& operator--(){_node = _node->_prev;return *this;}This operator--(int){This tmp(_node);_node = _node->_prev;return tmp;}//==重载和!=重载bool operator==(__list_iterator lit)const{return _node == lit._node;}bool operator!=(__list_iterator lit)const{return !(_node == lit._node);}};//反向迭代器//对正向迭代器的封装,从而得到我们想要的操作template<class T,class Ref,class Ptr>class ReverseIterator{typedef __list_iterator<T, Ref, Ptr> iterator;typedef	ReverseIterator<T, Ref, Ptr> reverse_iterator;iterator _it;ReverseIterator(iterator it):_it(it){}public:Ref operator*(){iterator tmp = _it;return *(--tmp);}Ptr operator->(){return &(operator*());}reverse_iterator& operator++(){--_it;return *this;}reverse_iterator operator++(int){reverse_iterator tmp = *this;--_it;return tmp;}reverse_iterator& operator--(){++_it;return *this;}reverse_iterator operator--(int){reverse_iterator tmp = *this;++_it;return tmp;}bool operator!=(const reverse_iterator& rit){return _it != rit._it;}bool operator==(const reverse_iterator& rit){return _it == rit._it;}};//listtemplate<class T>class list{typedef ListNode<T> Node;typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef ReverseIterator<T, T&, T*> reverse_iterator;typedef ReverseIterator<T, const T&, const T*> const_reverse_iterator;public://构造list(){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}//拷贝构造list(const list<T>& lt)//list(const list& lt){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;for (auto& e : lt){push_back(e);}_size = lt._size;}//交换void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}//=重载list<T> operator=(list<T> lt){swap(lt);return *this;}//析构~list(){Node* cur = _head->_prev;while (cur != _head){Node* tmp = cur->_next;delete cur;cur = tmp;}delete _head;_head = nullptr;}//迭代器iterator begin(){return _head->_next;}const_iterator begin()const{return _head->_next;}iterator end(){return _head;}const_iterator end()const{return _head;}reverse_iterator rbegin(){return reverse_iterator(end());}const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rend()const{return const_reverse_iterator(begin());}//插入(默认在pos前插入)iterator insert(iterator pos, const T& val){Node* newnode = new Node(val);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;cur->_prev = newnode;newnode->_next = cur;++_size;//隐式类型转换//返回指针类型,然后用类类型接收,会调用构造return newnode;}//删除iterator earse(iterator pos){//头节点不能删除,否则析构时会报错assert(pos != end());Node* cur = pos->_node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}//尾插和尾删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());}//大小size_t size(){return _size;}//清理void clear(){iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}private://指向头节点Node* _head;size_t _size;};void test_iterator(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);auto it = lt.begin();while (it != lt.end()){cout << *it << " ";it++;}cout << endl;}
}

4. vector和list比较

vectorlist
底层顺序表,可扩容双向循环链表,带头节点
效率具有连续的空间,空间利用率高;访问元素效率高,支持随机访问;插入和删除元素效率低,需要挪动元素,时间复杂度为O(N)底层开辟节点,空间利用率低;访问元素效率低,不支持随机访问; 插入和删除元素效率高,时间复杂度为O(1)
迭代器是原生态指针;是随机迭代器,支持+/-等操作;无论是插入还是删除,都会导致迭代器失效(插入需要扩容,扩容后原来的迭代器失效)是对原生态指针的封装;是双向迭代器,不支持+/-等操作 ;删除会导致迭代器失效
应用适用于插入和删除操作少,访问多的情况适用于插入和删除操作多,访问少的情况

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

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

相关文章

Python项目开发案例————学生信息管理系统(附源码)

一、学生信息管理系统 本文使用Python语言开发了一个学生信息管理系统&#xff0c;该系统可以帮助教师快速录入学生的信息&#xff0c;并且对学生的信息进行基本的增、删、改、查操作&#xff1b;还可以实时地将学生的信息保存到磁盘文件中。 1.1 需求分析 为了顺应互联网时代…

软件测试及数据分析处理实训室建设方案

一 、系统概述 软件测试及数据分析处理是软件开发过程中的一项重要测试活动&#xff0c;旨在验证不同软件模块或组件之间的集成与交互是否正常。综合测试确保各个模块按照设计要求正确地协同工作&#xff0c;以实现整个软件系统的功能和性能。以下是软件测试及数据分析处理的一…

SpringMVC程序开发

前言&#xff1a; &#x1f4d5;作者简介&#xff1a;热爱编程的小七&#xff0c;致力于C、Java、Python等多编程语言&#xff0c;热爱编程和长板的运动少年&#xff01; &#x1f4d8;相关专栏Java基础语法&#xff0c;JavaEE初阶&#xff0c;数据库&#xff0c;数据结构和算法…

【位运算】算法实战

文章目录 一、算法原理常见的位运算总结 二、算法实战1. leetcode面试题01.01. 判断字符是否唯一2. leetcode268 丢失的数字3. leetcode371 两整数之和4. leetcode004 只出现一次的数字II5. leetcode面试题17.19. 消失的两个数字 三、总结 一、算法原理 计算机中的数据都以二进…

香港服务器怎么打开SSH

​  SSH是一种远程登录协议&#xff0c;可以通过加密方式在网络上安全地传输数据。它允许用户在远程服务器上执行命令&#xff0c;管理文件和目录&#xff0c;并进行其他系统管理任务。 如何打开SSH服务? 1.确认已安装OpenSSH服务器&#xff1a; 你可以通过命令sudoapt-geti…

开发一款AR导览导航小程序多少钱?ar地图微信小程序 ar导航 源码

随着科技的不断发展&#xff0c;增强现实&#xff08;AR&#xff09;技术在不同领域展现出了巨大的潜力。AR导览小程序作为其中的一种应用形式&#xff0c;为用户提供了全新的观赏和学习体验。然而&#xff0c;开发一款高质量的AR导览小程序需要投入大量的时间、人力和技术资源…

Sql Server导出数据库到另一个数据库

1.打开sql server数据库&#xff0c;连接到服务器后&#xff0c;找到需要导出的数据库&#xff0c;右击后选择 任务->导出数据。 2.点击 下一步。 3.身份验证可以使用SQL Server身份验证&#xff0c;就是当时建立连接时的用户名和密码&#xff0c;数据库名称使用默认的&…

Kafka生产者原理 kafka生产者发送流程 kafka消息发送到集群步骤 kafka如何发送消息 kafka详解

kafka尚硅谷视频&#xff1a; 10_尚硅谷_Kafka_生产者_原理_哔哩哔哩_bilibili ​ 1. producer初始化&#xff1a;加载默认配置&#xff0c;以及配置的参数&#xff0c;开启网络线程 2. 拦截器拦截 3. 序列化器进行消息key, value序列化 4. 进行分区 5. kafka broker集群 获取…

数据库为什么使用B+树而不是B树做索引

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

华为质量管理:从产品质量到用户体验,Kano模型成为新方向

目录 前言 华为质量管理的四个阶段 基于 IPD 如何做质量管理呢&#xff1f; CSDN相关课程 作者简介 前言 今天继续来谈谈华为流程体系中的质量管理过程。 通常来说质量具体是指产品的质量&#xff0c;也就是产品的使用价值及其属性。 产品再细分的话可以分为三个层次&a…

Python 数据分析——matplotlib 快速绘图

matplotlib采用面向对象的技术来实现&#xff0c;因此组成图表的各个元素都是对象&#xff0c;在编写较大的应用程序时通过面向对象的方式使用matplotlib将更加有效。但是使用这种面向对象的调用接口进行绘图比较烦琐&#xff0c;因此matplotlib还提供了快速绘图的pyplot模块。…

《vue3实战》在created生命周期中运用slice()方法结合element plus组件实现电影评价系统的分页

目录 前言 电影评价系统的分页是什么&#xff1f;它具体的作用体现在哪些方面&#xff1f; 一、slice的含义、语法和作用以及created的作用 slice是什么&#xff1f;slice有什么语法&#xff1f;slice的作用体现在哪些方面&#xff1f; created生命周期的作用&#xff1a;…

K8S cluster with multi-masters on Azure VM

拓扑参考&#xff1a; 在 Azure VM 实例上部署 KubeSphere 基础模板 需要修改 IP 地址和 VM Image的可以在模板中修改。 {"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#","contentVersion": &q…

云计算存储类型

一、共享存储模式 NAS: ①一种专门用于存储和共享文件的设备&#xff0c;它通过网络连接到计算机或其他设备&#xff0c; 提供了一个中心化的存储解决方案 ②存储网络使用IP网络 &#xff0c;数据存储共享基于文件 ③本质上为:NFS和CIFS文件共享服务器 ④提供的不是一个磁盘块…

python使用 flask+vue 制作前后端分离图书信息管理系统

目录标题 前言制作前后端分离图书信息管理系统的思路&#xff1a;素材代码效果展示 后端部分接口部分前端部分尾语 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 哈喽兄弟们&#xff0c;今天咱们来用Python实现一个前后端分离的图书信息管理系统。 制作前后端分离图书信…

【IEEE会议】2023年第三届IEEE数字化社会与智能系统国际学术会议(DSInS 2023)

2023年第三届IEEE数字化社会与智能系统国际学术会议&#xff08;DSInS 2023) 2023 3rd International Conference on Digital Society and Intelligent Systems 由西南交通大学主办&#xff0c;悉尼科技大学、四川大学、中南大学社会计算研究中心、西南财经大学、武汉理工大学…

React 18 用 State 响应输入

参考文章 用 State 响应输入 React 控制 UI 的方式是声明式的。不必直接控制 UI 的各个部分&#xff0c;只需要声明组件可以处于的不同状态&#xff0c;并根据用户的输入在它们之间切换。这与设计师对 UI 的思考方式很相似。 声明式 UI 与命令式 UI 的比较 当设计 UI 交互时…

《存储IO路径》专题:数据魔法师DMA

初识DMA 大家好,今天我要给大家介绍一位在计算机世界中不可或缺的魔法师——DMA(Direct Memory Access)。让我们一起揭开这位魔法师的神秘面纱,看看它是如何让数据在内存之间自由穿梭的。 DMA这位魔法师可是大有来头。在现代计算机系统中,CPU、内存和各种设备之间需要进…

线性代数的学习和整理4: 求逆矩阵的多种方法汇总

目录 原始问题&#xff1a;如何求逆矩阵&#xff1f; 1 EXCEL里&#xff0c;直接可以用黑盒表内公式 minverse() 数组公式求A- 2 非线性代数方法&#xff1a;解方程组的方法 3 增广矩阵的方法 4 用行列式的方法计算&#xff08;未验证&#xff09; 5 A-1/|A|*A* &…

redis持久化机制 事务详解

目录 前言&#xff1a; 持久化机制 RDB&#xff08;Redis DataBase&#xff09; 手动触发 save bgsave 自动触发 RDB特点 AOF&#xff08;append only file&#xff09; 缓冲区刷新策略 重写机制 aof重写流程 混合持久化 事务 事务操作命令 WATCH WATCH实现原…