STL:List从0到1

请添加图片描述

在这里插入图片描述

🎉个人名片

🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🙈个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉
————————————————

🎉文章简介

🎉本篇文章将 介绍如何使用C++编写代码来实现一个类似于STL中的List容器 相关知识进行分享!
💕如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加 油,一起奔跑,让我们顶峰相见!!!🎉🎉🎉
——————————————————

一.前言

这篇文章将介绍如何使用C++编写代码来实现一个类似于STL中的List容器。 list是一个可以在常数范围内在任意位置进行插入和删除的序列式容器。在这篇文章中,你将学习并实现List的常见功能,如添加元素、删除元素等。通过实现自己的List容器,你将更好地熟悉List的使用及相关特性,并提升对C++语言的理解和掌握。
————————————————

二.List的介绍

List文档介绍链接: link

1. list是一个可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代;
2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素;
3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效;
4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好(不需要挪动数据);
5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素);

三.List的结构及模拟实现

一.底层结构

List底层是一个带头双向循环链表

如图:
在这里插入图片描述
在这里插入图片描述
库里面的begin() 与end() 返回的节点位置:

begin()返回的是头节点的下一个节点;
而end()返回的是头节点;

二.List的模拟实现

重点::迭代器的实现

1. 构造函数
template<class T>
struct ListNode
{ListNode<T>(const T& x=T())    :_next(nullptr),_prev(nullptr),_val(x){}ListNode<T>* _next;ListNode<T>* _prev;T _val;
};

库里面的List类的构造函数是另写一个函数,因为这个函数拷贝构造会使用,然后复用它,所以我们也这样实现;

template<class T>
class List
{
public:void empty_List(){_phead = new node;_phead->_next = _phead;_phead->_prev = _phead;}List(){empty_List();}
}
2. 拷贝构造函数
List(const List<T>& lt)
{empty_List();     //初始化for (const auto& e : lt)    {push_back(e);        //将lt里面的数据依次尾插}
}
3. 插入函数

思路:记录前一个和后一个节点,然后连接

在这里插入图片描述

iterator insert(iterator pos, const T& x)
{node* newnode = new node(x);    //构造一个节点node* next = pos._node;         node* prev = next->_prev;      //记录前一个newnode->_next = next;         next->_prev = newnode;         //链接newnode->_prev = prev;prev->_next = newnode;return pos;
}
4. 尾插函数

复用insert函数

void push_back(const T& x)
{
/*	node* newnode = new node(x);node* tail = _phead->_prev;tail->_next = newnode;newnode->_prev = tail;       //不复用的写法newnode->_next = _phead;_phead->_prev = newnode;*/insert(end(), x);
}
5. 头插函数

复用insert函数

	void push_front(const T& x){insert(begin(),x);}
6. 删除函数
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;                  //释放掉该节点return next;                       //返回删除元素的下一个节点
}
7. 尾删函数

复用删除函数

	void pop_back(){//erase(end()._node->_prev);erase(--end());       //头节点的前指针指向的是最后一个节点}
8. 头删函数

复用删除函数

	void pop_front(){erase(begin());     }
9. 迭代器的实现

因为链表的底层物理空间不是连续的,所以不能使用原生指针类实现。因为原生指针++,可以找到下一个数据,但是链表的节点与节点之间不是连续的,指针++,不能找到下一个节点,所以我们需要操作符重载,改变 ++, != ,* 等操作符的行为;又因为节点指针是内置类型,不能进行操作符重载,所以我们只能将它进行封装,封装在一个类里面,进行重载;

template<class T>
struct __List_iterator       
{typedef ListNode<T> node;typedef __List_iterator<T> self;__List_iterator(node* node)       //构造函数:_node(node){}self& operator++()               //运算符的重载{_node = _node->_next;       //前置++,返回++后的值return *this;}self& operator++(int){self tmp(_node);         //保存++前的值_node = _node->_next;return tmp;         //返回++前的值}self& operator--(){_node = _node->_prev;return *this;}self& operator--(int){self tmp(_node);_node = _node->_prev;return tmp;}T& operator*(){return _node->_val;}bool operator!=(const self& s){return s._node!= this->_node;}bool operator==(const self& s){return s._node == this->_node;}node* _node;
};
10. 赋值运算符重载

传统写法:

	void clear(){iterator lt = begin();while (lt != end()){lt = erase(lt);}}
//lt1=lt2
List<T>& operator=(const List<T>& lt)
{clear();                                 //清空函数,将链表中的有效数据删除掉,保留头节点for (const auto& e : lt){push_back(e);            //依次尾插}return *this;
}

现代写法:

void swap(List<T>& lt)
{std::swap(_phead, lt->_phead);
}
//lt1=lt2
List<T>& operator=(List<T> lt)    //lt是lt2的拷贝构造
{swap(lt);      //交换lt与lt1return *this;    //返回
}
补充知识:

typedef 放在类里面与外面的区别:
如果是放在公有里面,则类外面也可以使用,但是要指定类域;
如果是私有的话,则类外面不能使用;

三.总代码:

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;namespace L
{template<class T>struct ListNode{ListNode<T>(const T& x=T()):_next(nullptr),_prev(nullptr),_val(x){}ListNode<T>* _next;ListNode<T>* _prev;T _val;};template<class T>struct __List_iterator{typedef ListNode<T> node;typedef __List_iterator<T> self;__List_iterator(node* node):_node(node){}self& operator++(){_node = _node->_next;return *this;}self& operator++(int){self tmp(_node);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self& operator--(int){self tmp(_node);_node = _node->_prev;return tmp;}T& operator*(){return _node->_val;}bool operator!=(const self& s){return s._node!= this->_node;}bool operator==(const self& s){return s._node == this->_node;}node* _node;};template<class T>class List{public:typedef ListNode<T> node;typedef __List_iterator<T>  iterator;iterator begin(){return iterator(_phead->_next);}iterator end(){return iterator(_phead);}void empty_List(){_phead = new node;_phead->_next = _phead;_phead->_prev = _phead;}List(){empty_List();}List(const List<T>& lt){empty_List();for (const auto& e : lt)    //引用更好,如果T类型是自定义类型的话{push_back(e);}}//lt1=lt2List<T>& operator=(const List<T>& lt){clear();for (const auto& e : lt){push_back(e);}return *this;}void swap(List<T>& lt){std::swap(_phead, lt->_phead);}//lt1=lt2List<T>& operator=(List<T> lt){swap(lt);return *this;}void clear(){iterator lt = begin();while (lt != end()){lt = erase(lt);}}~List(){clear();delete _phead;_phead = nullptr;}void push_back(const T& x){/*	node* newnode = new node(x);node* tail = _phead->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _phead;_phead->_prev = newnode;*/insert(end(), x);}void push_front(const T& x){insert(begin(),x);}iterator insert(iterator pos, const T& x){node* newnode = new node(x);node* next = pos._node;node* prev = next->_prev;newnode->_next = next;next->_prev = newnode;newnode->_prev = prev;prev->_next = newnode;return pos;}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;return next;}void pop_back(){//erase(end()._node->_prev);erase(--end());}void pop_front(){erase(begin());}private:node* _phead;};

请添加图片描述

0

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

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

相关文章

mysql 排序底层原理解析

前言 本章详细讲下排序&#xff0c;排序在我们业务开发非常常见&#xff0c;有对时间进行排序&#xff0c;又对城市进行排序的。不合适的排序&#xff0c;将对系统是灾难性的&#xff0c;这个不是危言耸听。可能有些人会想&#xff0c;对于排序mysql 是怎么实现的&#xff0c;…

Linux 学习笔记(16)

十六、 计划任务 在很多时候为了自动化管理系统&#xff0c;我们都会用到计划任务&#xff0c;比如关机&#xff0c;管理&#xff0c;备份之类的操作&#xff0c;我 们都可以使用计划任务来完成&#xff0c;这样可以是管理员的工作量大大降低&#xff0c;而且可靠度更好。 l…

VS Code上,QT基于cmake,qmake的构建方法(非常详细)

VS Code上,QT基于cmake&#xff0c;qmake的构建方法 1 前言2 QT基于cmake的构建方法2.1 VS Code关键插件安装2.2 系统环境变量配置2.3 VS Code中&#xff0c;环境变量配置2.4 Cmake新建一个新的Porject 3 QT基于qmake的构建方法 1 前言 最近&#xff0c;由于认证了github的学生…

力扣111---二叉树的最小深度(简单题,Java,递归+非递归)

目录 题目描述&#xff1a; &#xff08;递归&#xff09;代码&#xff1a; &#xff08;非递归、层次遍历&#xff09;代码&#xff1a; 题目描述&#xff1a; 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说…

【echarts中解决适配窗口大小的问题】

适配窗口大小 一、基础适配方案&#xff1a;remflexible.js布局二、echart图表适配1.resize函数2.使用resize的前提&#xff01;重点&#xff01;不然resize极有可能失效 一、基础适配方案&#xff1a;remflexible.js布局 vscode插件&#xff1a;cssrem 编写好的less文件保存后…

数据结构 第3章:栈与队列

文章目录 1. 栈1.1 栈的基本概念1.2 栈的基本操作1.3 栈的顺序存储实现1.4 栈的链式存储实现 2. 队列2.1 队列的基本概念2.2 队列的基本操作2.3. 队列的顺序存储实现2.4 队列的链式存储实现2.5 双端队列 3. 栈与队列的应用3.1 栈在括号匹配中的应用3.2 栈在表达式求值中的应用3…

YOLOv7_pose-Openvino和ONNXRuntime推理【CPU】

纯检测系列&#xff1a; YOLOv5-Openvino和ONNXRuntime推理【CPU】 YOLOv6-Openvino和ONNXRuntime推理【CPU】 YOLOv8-Openvino和ONNXRuntime推理【CPU】 YOLOv7-Openvino和ONNXRuntime推理【CPU】 YOLOv9-Openvino和ONNXRuntime推理【CPU】 跟踪系列&#xff1a; YOLOv5/6/7-O…

【Linux】从零开始认识进程 — 前篇

我从来不相信什么懒洋洋的自由。我向往的自由是通过勤奋和努力实现的更广阔的人生。。——山本耀司 从零开始认识进程 1 认识冯诺依曼体系2 操作系统3 进程3.1 什么是进程&#xff1f;&#xff1f;&#xff1f;3.2 进程管理PCB 3.3 Linux中的进程深入理解 3.4 进程创建总结 送给…

SpringBoot实战项目——博客笔记项目

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍二、项目的整体框架 2.1 数据库模块 2.2 前端模块 2.3 后端模块三、项目图片展示四、项目的实现 4.1 准备工作 4.…

Transformer代码从零解读【Pytorch官方版本】

文章目录 1、Transformer大致有3大应用2、Transformer的整体结构图3、如何处理batch-size句子长度不一致问题4、MultiHeadAttention&#xff08;多头注意力机制&#xff09;5、前馈神经网络6、Encoder中的输入masked7、完整代码补充知识&#xff1a; 1、Transformer大致有3大应…

AcWing 848. 有向图的拓扑序列

#include<iostream> #include<cmath> #include<queue> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; const int N1e510; int n,m,a,b; int e[N],ne[N],h[N],idx; int d[N],top[N],cnt1;//top是拓扑排序…

香港理工大学主办!2024年第八届电力能源系统与应用国际会议(ICoPESA 2024)即将召开!

2024年第八届电力能源系统与应用国际会议&#xff08;ICoPESA 2024&#xff09; 2024年6月24日-26日 中国香港 ICoPESA 2024-Hong Kong (icpesa.org)https://icpesa.org/index.html 会议组织单位 会议出版及检索&#xff1a; 会议录用并注册的论文将由IEEE出版&#xff0c;…

SQL Server错误:15404

执行维护计划失败&#xff0c;提示SQL Server Error 15404 无法获取有关... 异常如下图&#xff1a; 原因&#xff1a;数据库用户名与计算机名称不一致 解决办法&#xff1a;1.重名称数据库用户名 将前缀改成计算机名 2.重启SQL Server代理

Mybatis sql 控制台格式化

package com.mysql; import org.apache.commons.lang.StringUtils; import org.apache.ibatis.logging.Log;import java.util.*;/*** Description: sql 格式化* Author: DingQiMing* Date: 2023-07-17* Version: V1.0*/ public class StdOutImpl implements Log {private stati…

【消息队列开发】 测试MessageFileManager(对硬盘中的消息操作)类

文章目录 &#x1f343;前言&#x1f384;测试流程&#x1f334;准备工作&#x1f332;测试创建队列功能&#x1f333;测试统计文件的读写&#x1f38b;测试将相应消息放入文件中&#x1f38d;测试读文件里的消息到内存&#x1f340;测试删除消息&#x1f60e;测试垃圾回收⭕总…

【设计模式】一、设计模式概述

文章目录 一、设计模式概述&#xff08;一&#xff09;设计模式是什么1. 设计模式的定义2. 设计模式的组成要素3、常用设计模式一览表 &#xff08;二&#xff09;设计模式的优点&#xff08;用途&#xff09;※ 本文小结 一、设计模式概述 &#xff08;一&#xff09;设计模式…

复杂网络——半局部中心法

一、概述 由于最近写论文需要使用复杂网络知识中的半局部中心法&#xff0c;但是截止目前来说&#xff0c;网上几乎搜索不到有关的MATLAB程序代码&#xff0c;只有一篇用Python编写的程序&#xff0c;我的电脑中没有python&#xff0c;所以我花费一些时间&#xff0c;利用matla…

基于SpringBoot+Vue交流和分享平台的设计与实现(源码+部署说明+演示视频+源码介绍)

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

Day44-sersync企业实时复制实战

Day44-sersync企业实时复制实战 1. sersync实时复制工具介绍1.1 sersync工具简介1.2 sersync特点1.3 sersync图解原理1.4 sersyncrsync实时复制方案项目实践1.4.1 图解项目方案架构及实现原理1.4.2 确保远程数据传输服务部署完成1.4.3 检查当前系统nfs01是否支持inotify实时监控…

008:安装Docker

安装Docker 如果不太熟悉Linux命令&#xff0c;不想学习Linux命令&#xff0c;可以直接看文末NAS面板章节&#xff0c;通过面板&#xff0c;像使用Window一样操作NAS。 一、安装 Docker 1.安装 Docker wget -qO- https://get.docker.com/ | sh2.启动 Docker 服务 sudo sys…