【C++】list详解及模拟实现

目录

1. list介绍 

2. list使用

2.1 修改相关

2.2 遍历 

2.3 构造

2.4 迭代器

2.5 容量相关

2.6 元素访问

2.7 操作相关

3. 模拟实现

3.1 节点类

3.1.1 初始结构

3.1.2 节点的构造函数

3.2 迭代器类

3.2.1 初始结构

3.2.2 迭代器++

3.2.3 迭代器-- 

3.2.4 解引用重载 

3.2.5 比较重载 

3.3 链表类

3.3.1 初始结构

3.3.2 初始化链表

3.3.3 默认成员函数 

3.3.3.1 无参构造

3.3.3.2 析构

3.3.3.3 拷贝构造

3.3.3.4 赋值重载

3.3.4 Iterators(迭代器)

3.3.4.1 const迭代器

3.3.5 Modifiers(修改相关) 

3.3.5.1 insert(pos插)

3.3.5.2 erase(pos删)

3.3.5.3 push_back(尾插)与push_front(头插)

3.3.5.4 pop_front(头删)与pop_back(尾删)

3.3.5.5 clear(清除节点)

3.3.6 size(返回数据个数)

4. 打印

4.1 不同容器的打印

5. list和vector的区别


1. list介绍 

1. list是一个带头双向循环链表。

2. list的声明,一个模板参数还有一个空间配置器。

3. Lists are sequence containers that allow constant time insert and erase operations anywhere within the sequence, and iteration in both directions.

4. 大框架:默认成员函数,迭代器,容量相关,元素访问,修改相关,排序,合并等。

2. list使用

2.1 修改相关

1. 支持头插,头删,尾插,尾删,pos插,pos删。

void test1()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);
}

2. assign是赋值,可以用迭代器区间赋值或n个val赋值。

2.2 遍历 

1. list不再支持方括号[ ]。

2. 主要还是用迭代器进行遍历,迭代器是内嵌类型,一般用typedef或内部类实现。

3. 支持了迭代器就支持范围for,因为范围for的底层就是迭代器。

void test1()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;for (auto e : lt){cout << e << " ";}cout << endl;
}

2.3 构造

1. 无参构造,n个val构造,迭代器区间构造,拷贝构造。 

2.4 迭代器

1. 有正向迭代器和反向迭代器,并且各自有const版本。

2. 虽然说新加了cbegin这些const系列,但其实begin本身也有const版本。

2.5 容量相关

1. 判空,返回数据个数,max_size没什么意义。

2.6 元素访问

1. 访问头和尾。

2.7 操作相关

1. reverse,逆置

void test2()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);for (auto e : lt){cout << e << " ";}cout << endl;lt.reverse();for (auto e : lt){cout << e << " ";}cout << endl;
}

2. sort,排序,默认是升序,降序需要用到仿函数。

void test3()
{list<int> lt;lt.push_back(5);lt.push_back(3);lt.push_back(1);lt.sort();//lt.sort(greater<int>());for (auto e : lt){cout << e << " ";}cout << endl;
}

3. merge,两个链表归并到一起。

4. unique,去重,要求有序。

void test4()
{list<int> lt(5, 1);for (auto e : lt){cout << e << " ";}cout << endl;lt.unique();for (auto e : lt){cout << e << " ";}cout << endl;
}

5. remove,直接删除val值。

6. splice,转移节点。 

3. 模拟实现

3.1 节点类

3.1.1 初始结构

1. 管理节点的类模板,包含节点的数据,节点的前驱指针和后继指针。

	template<typename T>struct list_node{T _data; //节点数据list_node<T>* _prev; //前驱指针list_node<T>* _next; //后继指针};

3.1.2 节点的构造函数

1. 参数是节点数据,缺省值是该类型的无参匿名对象。

2. 初始化列表进行成员初始化,节点数据用传入的参数,指针初始为空。 

		list_node(cosnt T& data = T()):_data(data),_prev(nullptr),_next(nullptr){}

3.2 迭代器类

3.2.1 初始结构

1. 这里用struct而不是class,因为所有都可以公开,不受访问限定符限制。

2. 成员是一个节点类型的指针。

3. 构造函数,传入一个节点类型的指针,在初始化列表初始化。

	template<typename T>struct list_iterator{typedef list_node<T> node;node* _cur; //迭代器成员//构造list_iterator(const node*& cur):_cur(cur){}};

3.2.2 迭代器++

1. 前置++,指针指向自己的后一个节点,返回自己的引用。

		list_iterator& operator++(){_cur = _cur->_next;return *this;}

2. 后置++,先把自己拷贝给tmp然后++,返回tmp。后置的参数需要一个int作为标识。

		list_iterator operator++(int){list_iterator tmp(*this);_cur = _cur->_next;return tmp;}

3.2.3 迭代器-- 

1. 前置--,指针指向自己的前一个节点,返回自己的引用。

		list_iterator& operator--(){_cur = _cur->_prev;return *this;}

2. 后置--,先把自己拷贝给tmp然后--,返回tmp。

		list_iterator operator--(int){list_iterator tmp(*this);_cur = _cur->_prev;return tmp;}

3.2.4 解引用重载 

1. *,解引用重载,返回节点数据的引用。

2. ->,箭头解引用,返回节点数据的地址。这里有两个箭头但被编译器省略了一个,第一个箭头是获取节点中数据成员的地址,第二个箭头是通过这个地址获取数据成员内的成员,因为数据成员可能是自定义类型。

		T& operator*(){return _cur->_data;}T* operator->(){return &_cur->_data;}

3.2.5 比较重载 

1. !=重载,和其他迭代器比较,传入迭代器的引用,比较它们的成员。

2. ==重载,传入一个迭代器,进行成员比较。

		bool operator==(const list_iterator& it){return _cut == it._cut;}bool operator!=(const list_iterator& it){return !(*this == it);}

3.3 链表类

3.3.1 初始结构

1. 管理链表的类模板,成员只有头结点,这个链表是带头双向循环链表。

namespace lyh
{//带头循环双向链表template<typename T>class list{public:typedef list_node<T> node;private:node* _head; //链表头结点};
}

3.3.2 初始化链表

1. 创建第一个节点也就是头结点。

2. 前驱指针指向自己,后继指针指向自己。

		void ListInit(){_head = new node;_head->_prev = _head;_head->_next = _head;}

3.3.3 默认成员函数 

3.3.3.1 无参构造

1. 直接调用初始化。​​​​​​​

		list(){ListInit();}
3.3.3.2 析构

1. 复用clear,再释放头结点然后置空,因为clear不清头结点。 

		~list(){clear();delete _head;_head = nullptr;}
3.3.3.3 拷贝构造

1. 先调用初始化函数生成头结点。

2. 用范围for遍历传入的链表,不断给自己尾插。

		list(cosnt list& lt){ListInit();for (auto e : lt){push_back(e);}}
3.3.3.4 赋值重载

1. 传入一个链表,拷贝构造给形参。

2. 将自己和形参交换,交换成员。

3. 返回自己的引用。

		void swap(const list& lt){std::swap(_head, lt._head);}list& operator=(list lt){swap(lt);return *this;}

3.3.4 Iterators(迭代器)

1. list类外写了迭代器对象,list类内提供begin和end。

2. begin,返回开始位置的迭代器,返回头结点的下一个节点,会隐式类型转换。

3. end,返回最后一个位置的下一个位置的迭代器,就是头节点,返回地址会隐式类型转换成迭代器。

		iterator begin(){return _head->_next;}iterator end(){return _head;}
3.3.4.1 const迭代器

1. 在写一个const迭代器类,相比原本的迭代器就是不能修改指向的内容。

2. 修改内容是通过解引用修改的,所以需要把和解引用的函数修改一下,把解引用的返回值加一个const。

3. 同时在list类提供const版本的begin和end,参数加一个const,返回值是const迭代器。


1. 上面这种方法会造成代码冗余,接下来的方法可以复用代码。

2. 就算类模板相同,只要模板参数不同就是不同的类型。

3. 增加两个模板参数,一个代表引用,一个代表指针,这两个模板参数写在解引用返回值的位置,根据你传什么模板参数,我的返回值就是什么样的,因为迭代器与const迭代器只有解引用的返回值有差别,所以把这两个返回值变成模板参数自己传,其他代码都可以复用。

4. 在list类里面定义迭代器类型和cosnt迭代器类型,这里可以把模板参数写好,然后提供const版本的begin和end。

​​​​​​​

3.3.5 Modifiers(修改相关) 

3.3.5.1 insert(pos插)

1. 传入一个迭代器和节点数据,返回的迭代器指向新插入的节点。

2. 先把迭代器指向的位置赋值给cur,再获取迭代器指向位置的前一个节点prev,建新节点new,new插入在prev和cur之间。

3. 这里迭代器不失效。

		iterator insert(iterator pos, const T& val){node* cur = pos._cur;node* prev = cur->_prev;node* newnode = new node(val);prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return newnode;}
3.3.5.2 erase(pos删)

1. 传入迭代器,返回下一个位置的迭代器。

2. 把迭代器指向的位置赋值给cur,获取迭代器的前一个位置prev和后一个位置next。

3. 将prev和next连接,释放cur。

4. 删除后迭代器失效。

		iterator erase(iterator pos){node* cur = pos._cur;node* prev = cur->_prev;node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;return next;}
3.3.5.3 push_back(尾插)与push_front(头插)

1. 传入新节点的节点数据,无返回值。

2. 复用insert,尾插在end迭代器前面插入,头插在begin迭代器前面插入。

		//尾插void push_back(const T& val){insert(end(), val);}//头插void push_front(const T& val){insert(begin(), val);}
3.3.5.4 pop_front(头删)与pop_back(尾删)

1. 无参无返。

2. 复用erase,头删删除begin迭代器指向的位置,尾删删除end前一个位置。

		//头删void pop_front(){erase(begin());}//尾删void pop_back(){erase(--end());}
3.3.5.5 clear(清除节点)

1. 用迭代器遍历,然后不断erase。 

		void clear(){iterator it = begin();while (it != end()){it = erase(it);}}

3.3.6 size(返回数据个数)

1. 这里需要加一个size成员用来记录数据个数。

2. 初始化函数把size置0,insert函数++size,erase函数--size,交换成员也要多一个。

		size_t size(){return _size;}private:node* _head; //链表头结点size_t _size; //数据个数

完整代码:List/List · 林宇恒/code-cpp - 码云 - 开源中国 (gitee.com)

4. 打印

1. 这里的list<T>只是类模板还没实例化,不能去取const_iterator。 

2. 因为静态成员变量也可以通过类域访问,然后list<T>是未实例化的类模板,编译器不能去里面找,所以这里编译器分不清是静态成员变量还是内嵌类型。

3. 在前面加一个typename就是告诉编译器这是一个内嵌类型,等实例化之后再去里面取。

4.1 不同容器的打印

 

5. list和vector的区别

1. 随机访问肯定用vector。大量头部,中部的修改肯定用list。vector适合尾插。 

2. 迭代器erase都会失效,list insert不会,vector会。

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

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

相关文章

path_provider插件的用法

文章目录 1. 概念介绍2. 实现方法3. 示例代码我们在上一章回中介绍了"如何实现本地存储"相关的内容,本章回中将介绍如何实现文件存储.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在上一章回中介绍的本地存储只能存储dart语言中基本类型的数值,如果遇到…

什么是远程过程调用(RPC)

进程间通信(IPC) 进程间通信(Inter-Process Communication)是指两个进程或者线程之间传送数据或者信号的一些技术或者方法。进程是计算机进行资源分配的最小的单位。每个进程都有自己独立的系统资源,而且彼此之间是相对隔离的。为了使得不同的进程之间能够互相访问,相互协…

AI-Talk开发板之wifi scan

一、说明 AI-Talk开发板使用ESP32-C3扩展WIFI通信功能&#xff0c;与CSK6011A通过SPI接口通信。 与处理器的信号连接&#xff1a; ESP32-C3需要烧录hosted固件&#xff0c;参考&#xff1a;AI-Talk开发板更新ESP32固件_esp32 固件-CSDN博客 二、工程 1、创建项目 进入exampl…

C语言中的一些小知识(三)

一、你了解printf()吗&#xff1f; 你知道下面代码的输出结果吗&#xff1f; int a123; printf("%2d \n",a); printf() 函数是 C 语言中用于格式化输出的标准函数&#xff0c;它允许你将数据以特定的格式输出到标准输出设备&#xff08;通常是屏幕&#xff09;。p…

Linux应用开发实验班——JSON-RPC

目录 前言 1.是什么JSON-RPC 2.常用的JSON函数 1.创建JSON 2.根据名字获取JSON 3.获取JSON的值 4.删除JSON 3.如何进行远程调用 服务器 客户端 4.基于JSON-RPC进行硬件操作 课程链接 前言 学习的课程是百问网韦东山老师的课程&#xff0c;对更详细步骤感兴趣的同学…

89个H5小游戏源码

下载地址&#xff1a;https://download.csdn.net/download/w2sft/89791650 亲测可用&#xff0c;代码完整&#xff0c;都是htmljs&#xff0c;保存到本地即可。 游戏截图&#xff1a;

3519嵌入式如何通过ssh 或者telnet连接嵌入式设备

需求 PC电脑连接嵌入式设备&#xff0c;已经能够连接串口&#xff0c;想要额外连接嵌入式设备&#xff0c;查看终端信息。 尝试了两种方法&#xff1a;1.通过SSH登录(失败) 2.通过telnet登录(成功) 问题描述 1.SSH登录 3519通过网线和串口线连接PC windows&#xff0c;并在…

JVM(HotSpot):虚拟机栈(JVM Stacks)之线程问题排查方法

文章目录 前言一、CPU占用过大二、程序运行很长时间没有结果三、总结 前言 本篇讲的排查都是基于Linux环境的。 一、CPU占用过大 这个一般是出现了死循环导致的。 1、先用top命令查看占用CPU的进程ID top2、再用ps命令查看对应的线程 就看一查看到对应的线程id ps H -eo …

hexo github部署,通过域名访问你的博客

hexo github部署&#xff0c;通过域名访问你的博客 hexo 常用命令hexo github 部署 在部署之前&#xff0c;了解一下hexo的常用命令 hexo 常用命令 hexo new "My New Post" # 新建文章 hexo n "My New Post"hexo generate # 生成静态文件 hexo ghexo serv…

2024必备中英互译利器全知道

现在英语目前还是学习最广泛的第二语言&#xff0c;所以很多资料都有英文的版本。如果外语不好&#xff0c;那中英互译翻译工具就能帮我们解决这个问题。今天我们一起来探讨下有哪些好用的翻译工具。 1.福昕在线翻译 链接直达>>https://fanyi.pdf365.cn/doc 这个工具…

无人机的避障的航迹规划详解!!!

一、无人机避障技术 视觉避障系统&#xff1a;通过安装在无人机上的摄像头捕捉周围环境的图像&#xff0c;利用计算机视觉技术对图像进行处理和分析&#xff0c;提取出障碍物的信息。这种方法直观、信息丰富&#xff0c;但在光线不足或变化多的情况下可能影响识别效果&#xf…

解决启动docker desktop报The network name cannot be found的问题

现象 deploying WSL2 distributions ensuring main distro is deployed: checking if main distro is up to date: checking main distro bootstrap version: getting main distro bootstrap version: open \wsl$\docker-desktop\etc\wsl_bootstrap_version: The network name…

【网络通信基础与实践番外一】多图预警之图解UDP和TCP前置知识

参考大佬的文章https://www.cnblogs.com/cxuanBlog/p/14059379.html 一、宏观架构中的传输层 在计算机中&#xff0c;任何一个可以交换信息的介质都可以称为端系统。计算机网络的运输层则负责把报文从一端运输到另一端&#xff0c;运输层实现了让两个互不相关的主机进行了逻辑…

【后端开发】JavaEE初阶—Theard类及常见方法—线程的操作(超详解)

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解多线程的知识哟~~~&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;【后端开发】JavaEE初阶—线程的理解和编程实现-CSDN博客 &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondl…

Android OpenGLES2.0开发(三):绘制一个三角形

我们总是对陌生人太客气&#xff0c;而对亲密的人太苛刻 上一篇文章中&#xff0c;我们已经将OpenGL ES环境搭建完成。接下来我们就可以开始我们的绘图之旅了。该篇我们讲解最基本图形三角形的绘制&#xff0c;这是一切绘制的基础。在OpenGL ES的世界里一切图形都可以由三角形拼…

OrangePi 烧录镜像步骤

理解&#xff1a;第一步&#xff1a;烧录镜像。第二步&#xff1a;建立编译环境&#xff08;一般是PC端的Linux虚拟机&#xff09;和板卡端的文件连接。因为要传文件&#xff0c;一般用挂载的方法。第三步&#xff1a;软件程序的编译与部署。 第一步&#xff1a;烧录镜像步骤 …

数据分析:Python语言网络图绘制

文章目录 介绍加载R包类别导入数据下载数据画图介绍 网络图是一种图形表示法,用于展示实体之间的关系。在不同的领域中,网络图有着不同的含义和用途:在生物学中,网络图可以用来表示生物分子之间的相互作用,如蛋白质相互作用网络。 加载R包 import pandas as pd import …

Xcode 16 上传AppStore遇到第三方库 bitcode 的问题

Xcode 16 上传AppStore遇到第三方库 bitcode 的问题 最近两天更新了Xcode 16&#xff0c;然后正好要发布新版本的App&#xff0c;打包Adhoc没问题&#xff0c;但是上传AppStoreConnect或者TestFlight就不行解决方案参考资料 最近两天更新了Xcode 16&#xff0c;然后正好要发布新…

HTML+CSS学习笔记

目录 HTML 1.开发环境 2.创建HTML文件 3.HTML元素 3.1HTML文件结构 3.2HTML标签 3.3HTML属性​编辑​编辑 3.4HTML区块 3.4.1块元素 3.4.2行内元素 3.5HTML表单 CSS 1.CSS简介 2.CSS语法​编辑 3.CSS三种导入方式 内联样式 内部样式 外部样式 4.选择器​ 5.C…

sheng的学习笔记-AI-时序差分学习

AI目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 强化学习&#xff1a;sheng的学习笔记-AI-强化学习&#xff08;Reinforcement Learning, RL&#xff09;-CSDN博客 蒙特卡罗强化学习&#xff1a; sheng的学习笔记-AI-蒙特卡罗强化学习-CSDN博客 什么是时序差分学习 时序…