list下

文章目录

      • 注意:
      • const迭代器
        • 怎么写?
        • 运用场合?
      • insert
      • erase
      • 析构函数
      • 赋值和拷贝构造
        • 区别?
        • 拷贝构造不能写那个swap,为什么?
        • 拷贝构造代码
      • 面试问题
        • 什么是迭代器失效?
        • vector、list的区别?
      • 完整代码

注意:

delete 和delete[]之间不能用错
delete是单个;
delete是一个数组;
vector、string都是delete[];
list本质不是数组是列表,所以delete

const迭代器

怎么写?
		typedef __list_iterator<T, T&, T*> iterator; // 放public里面不然外面动不了T,就是用不了模板,私有的不能用typedef __list_iterator<T,const T&,const T*> const_iterator;//const迭代器//迭代器用节点的指针就行了iterator begin(){return iterator(_head->_next);//注意这里返回的是迭代器,不是_head头部指针、这个是list类里面的成员变量//现在是把头部指针_head传过去,然后迭代器调用他的拷贝函数;//这里面就是构造函数、因为传过去的是Node类型;}iterator end(){return iterator(_head);}//const_iteratorconst_iterator begin() const{return const_iterator(_head->_next); }const_iterator end() const{return const_iterator(_head);}

image.png
模板里面放多个参数,在传模板时候,如上图,右边框起来上面是普通的迭代器,下面有const,用哪种就会自动传过去,同时Self也是对应的迭代器;
image.png

运用场合?

一般const指针是不用的;
什么情况下去用?
传参给另一个函数用的时候会用到;
例如下面功能是打印的成员函数

	void print_list(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;}

insert

在pos位置插入,这个pos是一个迭代器,插入后这个节点以及前后节点的_next和_prev要注意怎么赋值;
cur是pos指向的当前节点;
newnode是新插入的节点;
image.png

		//insert//现在要的是列表里面的那两个指针next\prev;//迭代器里面就有_node存的是Node*类型;void insert(iterator pos,const T& x = T()){Node* cur = pos._node;//pos是迭代器所以调用他的成员函数用点符号"."虽然类似指针但是不能->,这个是指针用的Node* prev = cur->_prev;Node* newnode = new Node(x);newnode->_next = cur;newnode->_prev = prev;cur->_prev = newnode;prev->_next = newnode;}

写完insert,push_back和push_front就可以直接用insert的

		//头插void push_front(const T& x = T()){insert(begin(), x);}//尾插void push_back(const T& x = T()){//Node* tail = _head->_prev;//Node* newnode = new Node(x);//tail->_next = newnode;//newnode->_prev = tail;//newnode->_next = _head;//_head->_prev = newnode;//再pos是end()的时候插入,end()表示最后一个元素的后一个位置,所以插入这个位置就是尾插insert(end(), x);}

erase

头节点指向的迭代器就是end();
end()的意思是最后一个元素的后一个位置,那就是_head,这个头节点;
和insert类似,_next/_prev都要重新赋值一下:
image.png

		//erase,erase是要返回删除的位置的后一个位置的Node* erase(iterator pos){//cur里面存现在的地址//prev是cur上一个地址assert(pos  != end()); //头节点不能删Node* cur = pos._node;  Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;//delete[]必须是数组,所以要注意return next;}

头删除、和尾删除就可以用erase了

		//尾删void pop_back(){//erase(iterator(_head->_prev));erase(--end());}//头删除void pop_front(){erase(begin());}

析构函数

析构,栈里面的是先定义的后出去,现进后出;
析构是释放了还要置空;

		void clear(){Node* cur = _head->_next;while (cur != _head){_head->_next = cur->_next;delete cur;cur = _head->_next}_head = head->next = head->prev;//重新关联起来,双向带头循环列表;}//析构~list(){clear();detete _head;_head = nullptr;}

clear的作用是清空这个链表里面的内容,_head这个头节点是没有data的,所以是不用动的;
析构是直接这个链表对象空间释放了,所以_head也要释放;

赋值和拷贝构造

区别?

问:string为什么这边写了要先置位nullptr,然而这边的list没有呢?
答:
拷贝构造l1(l2),l1首先要初始化、至少里面是个nullptr,因为他还没有被创建出来;
赋值的话l1 = l2,首先你这个l1是不是已经是先定义出来的,所以不用初始化的;
image.png

拷贝构造不能写那个swap,为什么?

答:这样的话在传参数时就是又一个拷贝构造,那就会无限循环

拷贝构造代码
		//拷贝函数l1(l2)//首先l1是没有创建出来的,所以要初始化list(const list<T>& lt){//先初始化,list里面成员函数是什么?_head,_head里面的内容Node* _head;_head->_next = _head->_prev = _head;//往里面插入后面的值就行了//方法一/*const_iterator it = lt.begin();while (it != it.end()){push_back(*it);//运算符重载过*it了,传过去的是_node->_datait++;}*///方法二for (auto e : lt)//本质调用的迭代器{push_back(e);}}

在string和vector里面是这样的,for循环本质使用的是迭代器,有迭代器就有for循环,e理论上就是*it
image.png

面试问题

什么是迭代器失效?

迭代器失效具体内容

vector、list的区别?

vector是一个动态增长的数据
优点:支持随机访问operator[],排序、二分查找、堆算法等等可用到;
缺点:空间不够要增容、头部或者中间插入效率低o(n);

list是一个带头双向循环的链表
优点:任意位置插入效率高o(1);
缺点:不支持随机访问;

总结:list和vector相辅相成、是两个互补的容器

完整代码

test.c
在这里插入图片描述

#pragma once
namespace list_test
{template<class T>//struct__list_node,两个_这种取名方式一般表示一会这个会在别的里面用,在这里就表示,list类里面直接用的类外面定义的struct __list_code这个结构体struct __list_node{__list_node<T>* _next; // 别忘了这里要写<T>__list_node<T>* _prev;T _data;//列表需要构造函数来初始化__list_node(const T& x = T())//这个T(),指的是没有传值过来那就直接为0:_data(x),_next(nullptr)  ,_prev(nullptr){}};//struct迭代器__list_iteratortemplate<class T, class Ref, class Ptr>//这个就是三个模板参数struct __list_iterator{typedef __list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> Self;Node* _node;//构造函数,struct怎么写构造函数、就是看这个里面成员函数有哪些__list_iterator(Node* node):_node(node){}//构造传的是里面的成员函数、拷贝是传的类或者说这个结构体//浅拷贝,这个是默认函数、不用写的__list_iterator(const Self& it) {_node = it._node;}// operator*,读_node中的data,data的类型是T,所以函数返回值类型是TRef operator*(){return _node->_data;}//++Self& operator++(){_node = _node->_next;return *this;}//后置++Self operator++(int) //后置++里面就放个int,这是设计出来的伪参数,用来区分前后置用的{__list_iterator<T> tmp(*this); //直接拷贝函数、这个不用写、因为是浅拷贝,深拷贝才要写_node = _node->_next; //++(*this);return tmp;}//--Self& operator--(){_node = _node->_prev; //_node是指针return *this; //*this就是迭代器,this是指针指向迭代器}Self& operator--(int) //后置++里面就放个int,这是设计出来的伪参数,用来区分前后置用的{Self tmp(*this); //直接拷贝函数、这个不用写、因为是浅拷贝,深拷贝才要写//node = _node->_next;--(*this);return tmp;}//!=,两个迭代器之间不相等、迭代器里面的成员函数是_node,比的是这两个,就是他指向一个列表的地址,看这两个地址一样吗bool operator!=(const Self& it){return _node != it._node;}Ptr operator->(){return &_node->_data;//返回这个地址//指向这个地址,调用时第一个->返回其地址、第二个->返回地址上的值,迭代器做了优化,调用只需要一个->}};template<class T>class list{typedef __list_node<T> Node;public:typedef __list_iterator<T, T&, T*> iterator; // 放public里面不然外面动不了T,就是用不了模板,私有的不能用typedef __list_iterator<T,const T&,const T*> const_iterator;//const迭代器//迭代器用节点的指针就行了iterator begin(){return iterator(_head->_next);//注意这里返回的是迭代器,不是_head头部指针、这个是list类里面的成员变量//现在是把头部指针_head传过去,然后迭代器调用他的拷贝函数;//这里面就是构造函数、因为传过去的是Node类型;}iterator end(){return iterator(_head);}//const_iteratorconst_iterator begin() const{return const_iterator(_head->_next); }const_iterator end() const{return const_iterator(_head);}//构造函数list(){_head = new Node;//new node //这里面不用写成Node[],是因为[]是数组用的,这个就里面就开辟一个指针指向的地址空间,[]是一个数组的空间_head->_next = _head;_head->_prev = _head;}//insert//现在要的是列表里面的那两个指针next\prev;//迭代器里面就有_node存的是Node*类型;void insert(iterator pos,const T& x = T()){Node* cur = pos._node;//pos是迭代器所以调用他的成员函数用点符号"."虽然类似指针但是不能->,这个是指针用的Node* prev = cur->_prev;Node* newnode = new Node(x);newnode->_next = cur;newnode->_prev = prev;cur->_prev = newnode;prev->_next = newnode;}//头插void push_front(const T& x = T()){insert(begin(), x);}//尾插void push_back(const T& x = T()){//Node* tail = _head->_prev;//Node* newnode = new Node(x);//tail->_next = newnode;//newnode->_prev = tail;//newnode->_next = _head;//_head->_prev = newnode;//再pos是end()的时候插入,end()表示最后一个元素的后一个位置,所以插入这个位置就是尾插insert(end(), x);}//erase,erase是要返回删除的位置的后一个位置的Node* erase(iterator pos){//cur里面存现在的地址//prev是cur上一个地址assert(pos  != end()); //头节点不能删Node* cur = pos._node;  Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;//delete[]必须是数组,所以要注意return next;}//尾删void pop_back(){//erase(iterator(_head->_prev));erase(--end());}//头删除void pop_front(){erase(begin());}void clear(){Node* cur = _head->_next;while (cur != _head){_head->_next = cur->_next;delete cur;cur = _head->_next}_head = head->next = head->prev;//重新关联起来,双向带头循环列表;}//析构~list(){clear();detete _head;_head = nullptr;}//拷贝函数l1(l2)//首先l1是没有创建出来的,所以要初始化list(const list<T>& lt){//先初始化,list里面成员函数是什么?_head,_head里面的内容Node* _head;_head->_next = _head->_prev = _head;//往里面插入后面的值就行了//方法一/*const_iterator it = lt.begin();while (it != it.end()){push_back(*it);//运算符重载过*it了,传过去的是_node->_datait++;}*///方法二for (auto e : lt)//本质调用的迭代器{push_back(e);}}//赋值运算l1 = l2//方法一:list<T>& operator=(const list<T>& lt){//防止自己给自己赋值if (this != &lt)//用地址来比较{clear();//看clear函数,clear结束后就是初始化后的_head,所以也不用再写一遍_head的初始话for (auto e : lt)push_back(e);//就一行不用写{}了}return *this;//*this,解引用this迭代器就是这个list类的对象了l1}//方法二:list<T>& operator=(list<T> lt)//这里传参用到拷贝构造,lt是临时对象{swap(_head, lt._head)return *this;//*this,解引用this迭代器就是这个list类的对象了l1}private:Node* _head;};void test_list1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;}struct Date{int _year = 0;int _month = 1;int _day = 2;};void test_list2(){list<Date> lt;lt.push_back(Date());lt.push_back(Date());list<Date>::iterator it = lt.begin();//调用data,因为现在模板T就是date,传参传过去date是可以的while (it != lt.end()){cout << it->_year << " " << it->_month << " " << it->_day;++it;}cout << endl;}void print_list(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;}void test_list3(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);print_list(lt);lt.pop_front();lt.pop_back();print_list(lt);}
}

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

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

相关文章

4 课程分类查询

4 课程分类查询 4.1 需求分析 下边根据内容管理模块的业务流程&#xff0c;下一步要实现新增课程&#xff0c;在新增课程界面&#xff0c;有三处信息需要选择&#xff0c;如下图&#xff1a; 课程等级、课程类型来源于数据字典表&#xff0c;此部分的信息前端已从系统管理服…

【jetson笔记】vscode远程调试

vscode安装插件 vscode安装远程插件Remote-SSH 安装完毕点击左侧远程资源管理器 打开SSH配置文件 添加如下内容&#xff0c;Hostname为jetson IP&#xff0c;User为登录用户名需替换为自己的 Host aliasHostName 192.168.219.57User jetson配置好点击连接&#xff0c;控制台输…

66.Spring是如何整合MyBatis将Mapper接口注册为Bean的原理?

原理 首先MyBatis的Mapper接口核心是JDK动态代理 Spring会排除接口&#xff0c;无法注册到IOC容器中 MyBatis 实现了BeanDefinitionRegistryPostProcessor 可以动态注册BeanDefinition 需要自定义扫描器&#xff08;继承Spring内部扫描器ClassPathBeanDefinitionScanner ) 重…

【计算机网络】UDP协议与TCP协议

文章目录 一、端口号1.什么是端口号2.端口号范围划分3.认识知名端口号(Well-Know Port Number)4.netstat5.pidof 二、UDP协议1.UDP协议端格式2.UDP的特点3.面向数据报4.UDP的缓冲区5.UDP使用注意事项6.基于UDP的应用层协议 三、TCP协议1.TCP协议段格式1.1理解封装解包和分用1.2…

【数学建模】插值与拟合

文章目录 插值插值方法用Python解决插值问题 拟合最小二乘拟合数据拟合的Python实现 适用情况 处理由试验、测量得到的大量数据或一些过于复杂而不便于计算的函数表达式时&#xff0c;构造一个简单函数作为要考察数据或复杂函数的近似 定义 给定一组数据&#xff0c;需要确定满…

伸向Markdown的黑手,知名博客平台曝出LFI漏洞

如果你至今依然在坚持写博客&#xff0c;在知乎或其他自媒体平台上发表文章&#xff0c;那你应该对Markdown很熟悉了。这是一种轻量级标记语言&#xff0c;借此可以用纯文本格式编写文档&#xff0c;并用简单的标记设置文档格式&#xff0c;随后即可轻松转换为具备精美排版的内…

安装宝塔面板后k8s所在节点pod无法正常工作解决方法,kubernetes k8s 与宝塔面板冲突解决方法

在实际项目过程中我们使用了k8s 在生产环境中运行管理服务。 但是对服务器的状态管理我们使用了宝塔面板进行 K8s 版本1.2.8 宝塔面板 版本 8.05 操作步骤是这样的。 1.完成1.2.8 k8s的节点安装&#xff0c;并正常运行服务。 过程略 2.安装宝塔面板 ​ yum install -y …

vue中图片不显示问题 - vue中静态资源加载

文章目录 vue中图片不显示问题静态资源URL 转换规则webpack 静态资源处理 图片不显示问题问题描述解决办法1&#xff1a;使用require引入require is not defined 解决办法2&#xff1a;使用import引入解决办法3&#xff1a;将图片放进公共文件夹static或public vue中图片不显示…

PHP中一些特征函数导致的漏洞总结

第一部分&#xff1a; 特征函数 接触到几个常用的函数&#xff1a; \\ \\\ md5 intval strpos in_array preg_match str_replacephp用这些函数实现过滤一些代码&#xff0c;漏洞可能有一些特性&#xff0c;利用这些特征代码进行对比&#xff1b;账号密码对比&#xff1b;强制检…

ChatGPT无法胜任的五种编程任务

我喜欢把ChatGPT看作是StackOverflow的智能版&#xff0c;它大有帮助&#xff0c;但短期内不会取代专业人士。作为一名前数据科学家&#xff0c;ChatGPT问世后&#xff0c;我花了大量时间来试用它。其编程能力确实给我留下了深刻的印象。它可以从零开始生成非常有用的代码&…

核桃的数量---蓝桥杯

思路&#xff1a; 题目所代表的意思就是a,b,c这三个必须是核桃数量的因子&#xff0c;即a,b,c三个的最小公倍数 #include <iostream> #include <algorithm> using namespace std; // int main() { int a,b,c;cin>>a>>b>>c;int da*b/__gcd(a,b…

大数据处理,Pandas与SQL高效读写大型数据集

大家好&#xff0c;使用Pandas和SQL高效地从数据库中读取、处理和写入大型数据集&#xff0c;以实现最佳性能和内存管理&#xff0c;这是十分重要的。 处理大型数据集往往是一项挑战&#xff0c;特别是在涉及到从数据库读取和写入数据时。将整个数据集加载到内存中的传统方法可…

antdesignvue中使用VNode写法

1、使用场景 如图&#xff1a;消息提示框中&#xff0c;将数据中的数据单独一行显示 2、代码 let errorList res.result; //后端返回的数据例&#xff1a; ["1. 数据格式不正确","2. 数据已存在"]if(errorList&&errorList.length!0){this.$notif…

k8s的图形化工具---rancher

声明式&#xff1a;yaml文件 陈述式&#xff1a;命令行 k8s的图形化工具---rancher racher是一个开源的企业级多集群的k8s关联平台。 rancher和k8s区别&#xff1a; 都是为了容器的调度和编排系统&#xff0c;但是rancher不仅能调度&#xff0c;还能管理k8s集群&#xff0…

mac电脑安卓文件传输工具:Android File Transfer直装版

Android File Transfer&#xff08;AFT&#xff09;是一款用于在Mac操作系统上与Android设备之间传输文件。它允许用户将照片、音乐、视频和其他文件从他们的Android手机或平板电脑传输到Mac电脑&#xff0c;以及将文件从Mac上传到Android设备。 下载地址&#xff1a;https://w…

Unity New Input System 及其系统结构和源码浅析【Unity学习笔记·第十二】

转载请注明出处&#xff1a;&#x1f517;https://blog.csdn.net/weixin_44013533/article/details/132534422 作者&#xff1a;CSDN|Ringleader| 主要参考&#xff1a; 官方文档&#xff1a;Unity官方Input System手册与API官方测试用例&#xff1a;Unity-Technologies/InputS…

【项目日记(四)】第一层: 线程缓存的具体实现

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你做项目   &#x1f51d;&#x1f51d; 开发环境: Visual Studio 2022 项目日…

CC工具箱使用指南:【Excel导出图片】

一、简介 这是一个有点娱乐向的小工具。作用就是将Excel的内容导出成一个JPG图片&#xff0c;目前只针对Excel中的第一个sheet表。 说不出来实际作用在哪里&#xff0c;不过把一个长表快速导出图片&#xff0c;有时候也挺有意思&#xff0c;有兴趣可以试试。 二、工具参数介绍…

MySQL-进阶-索引

一、索引概述 1、介绍 2、有误索引搜索效率演示 3、优缺点 二、索引结构 1、B-Tree&#xff08;多路平衡查找树&#xff09; 2、BTree 3、Hash 三、索引分类 四、索引语法 1、语法 2、案例 五、SQL性能分析 1、查看执行频次 2、慢查询日志 3、show-profile 4、explain

【目标跟踪】多相机环视跟踪

文章目录 一、前言二、流程图三、实现原理3.1、初始化3.2、输入3.3、初始航迹3.4、航迹预测3.5、航迹匹配3.6、输出结果 四、c 代码五、总结 一、前言 多相机目标跟踪主要是为了实现 360 度跟踪。单相机检测存在左右后的盲区视野。在智能驾驶领域&#xff0c;要想靠相机实现无…