STL之my_list容器

前言:各位老铁好久不见了,今天分享的知识是自己实现一个简单的list容器,为什么我先跳过vector容器的自我实现呢?我个人觉得vector相对于list的自我实现简单一点,所以今天先分享实现my_list的知识

我们要实现my_list,首先我们要知道list有那些常用的接口,我们先看一看实现list的文档

实现list容器文档入口

在这里插入图片描述
list容器有这么多接口,我会从里面挑出常用的接口进行模拟实现。

list实现(这里讲的是带头的双向循环链表)

我们在数据结果中已经学习过list了,知道list内部结果主要包含三部分,一是存放的值,二是链接前面一个结点的指针,三是链接后面一个结点的指针。由于库里面也有已经实现好了的list,为了防止my_list和库里面的冲突,我们需要搞个命名空间封装起来,命名空间的名字随便用。

namespace ljy
{}

由于我们不知道list容器的类型是什么类型,所以我们需要搞个模板函数,对任意类型的list都适用。然后我们需要搞个类(私有的比较好,防止其他人修改成员变量)把list里面的成员给封装起来

namespace ljy
{template<class T>struct _list_node{_list_node<T>* _prev;_list_node<T>* _next;T _data;//任意类型的数据};
}

接下来我们需要把链表给初始化

namespace ljy
{template<class T>struct _list_node{_list_node<T>* _prev;_list_node<T>* _next;T _data;//任意类型的数据_list_node(const T& x = T())//这里是构造一个空的对象来充当缺省参数,防止没有提供参数从而导致编译器报错:_data(x), _prev(nullptr), _next(nullptr){}};
}

由于list不支持随机访问,我们只能通过迭代器进行访问list中的结点。所以我们先来实现list的迭代器的接口。

由于list迭代器底层是一个指针,所以我们如果需要访问list和修改list,就需要对指针进行解引用和取地址,因此我给list迭代器模板参数定义三个参数,一个是有关数据类型(T),一个是解引用(Ref),一个是取地址(Ptr)

//迭代器
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迭代器进行初始化

_list_iterator(Node* node):_node(node)
{}

我们需要分清对指针的*和->,一个是对指针解引用(表示取向指针指向的值),另一个是对指针取地址(表示指向结点的本身)

	//*Ref operator*(){return _node->_data;}
//->
Ptr operator->()
{return &_node->_data;
}

再接下来我们实现++和- -运算符的重载++和- - 分为前置++,前置- -,后置++和后置- -。前置和后置的区别是是否先返回值再进行++和- -

前置++

//前置++
Self& operator++()//返回的是this指针,出了作用域还存在,所以用引用返回
{_node = _node->_next;return *this;
}

后置++

//后置++       返回的是中间变量,出了作用域就不存在了,不需要使用引用返回
Self operator++(int)//在形参里面+int是为了和前置++区别开来。
{Self tmp(this);++(*this);return tmp;
}

前置- -

//前置--
Self& operator--()
{_node = _node->_prev;return *this;
}

后置- -

//后置--
Self operator--(int)
{Self tmp(this);_node = _node->_prev;return tmp;
}

然后再实现==和!=运算符重载

==运算符重载

bool operator==(const Self& lt)
{return _node == lt._node;
}

!=运算符重载

bool operator!=(const Self& lt)
{return _node != lt._node;
}

到这里list的迭代器就完成了。

接下来就到list的一些常用接口的实现

list的框架

template <class T>class list{typedef _list_node<T> Node;public:typedef _list_iterator<T,T*,T&> iterator;//普通迭代器typedef _list_iterator<T, T*, T&> const_iterator;//const迭代器private:Node* _head;};

返回头节点

//双向带头的循环链表(可修改头节点的位置和头节点指向的值)
iterator begin()
{//开始的结点在头节点的下一个结点//通过迭代器迭代寻找结点return iterator(_head->_next);
}
//通过const迭代器迭代寻找结点(不可修改头节点的位置和头节点指向的值)
const_iterator begin() const
{return const_iterator(_head->_next);
}

//双向带头的循环链表(可修改尾节点的位置和尾节点指向的值)

	iterator end(){//头结点指向的位置就是end位置return iterator(_head);}

//通过const迭代器迭代寻找结点(不可修改尾节点的位置和尾节点指向的值)

const_iterator end() const
{return const_iterator(_head);
}

然后实现在任意位置插入数据的接口

//在pos位置前插入数据void insert(iterator pos,const T& x){//先找出当前的结点Node* cur = pos._node;Node* prev = cur->_prev;//再开辟出一个新的结点Node* newnode = new Node(x);//再把prev newnode cur三个结点按前后顺序链接起来prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;}

再在任意插入位置插入数据的接口基础上实现头插和尾插

头插:就是在begin前一个位置插入

//头插
void push_front(const T& x)
{//直接在begin()前面的位置进行插入insert(begin(), x);
}

尾插:就是在头结点前一个位置进行插入,头节点前一个位置就是末尾
在这里插入图片描述

	//从尾部插入数据void push_back(const T& x){//end()就是头节点的前一个位置,也就是尾部return (end(), x);}

到这里插入数据的接口我们就实现完了,有插入数据必然就会有删除数据,所以接下来我们就开始实现删除数据。

首先我们先实现在任意位置删除数据,在文档中erase删除数据是将数据删除后返回当前数据的下一个位置。
在这里插入图片描述
在这里插入图片描述

	//在任意位置删除数据void erase(iterator pos, const T& x){//不能把头节点删除assert(pos != end());//先保存当前结点Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;delete cur;//再把结点链接起来prev->_next = next;next->_prev = prev;}

然后在在任意位置删除数据的接口的基础上,再实现头删和尾删。

头删:begin()函数返回的位置就是头

void pop_front(const T& x)
{erase(begin(), x);
}

尾删:end()函数获取的位置是尾结点的下一个位置,只要先给end()函数- -就能找到尾结点从而删掉尾结点。

//尾删
void pop_back(const T& x)
{erase(--end());
}

list的删除数据接口到这里就完成了,然后我们再给list写初始化函数(个人习惯,先写完接口再写初始化),构造函数,拷贝构造函数,赋值运算符重载,析构函数。

构造函数:由于我们我们这里的list是双向带头循环的链表,所以我们需要先开辟一个头节点出来,把头结点和自身链接起来。
在这里插入图片描述

list()
{//new出一个头结点_head = new Node;//让头节点指向自己_head->_next = _head;_head->_prev = _head;
}

拷贝构造函数:

//拷贝构造
//lt2(lt1)
list(const list<T>& lt)//传一个类对象过来
{//先构造出一个和lt一模一样的头节点,然后再直接把lt的数据插入到lt2中_head = new Node;_head->_next = _head;_head->_prev = _head;for (auto e : lt){push_back(e);//这里其实是this->push_back()}
}

赋值运算符重载(现代写法:借助第三方实现相对应的功能,再把原来的和第三方进行交换)

//operator=
//lt3=lt2
list<T>& operator=(list<T> lt)//这里创建对象借助了拷贝构造,lt2通过lt1进行拷贝构造
{//直接把lt3和lt2的头结点进行交换就可以了swap(_head = lt._head);//再返回this指针return *this;
}

总结:这次的文章分享list容器的底层代码知识,让我们懂得如何实现list容器的一些常用接口,希望我们能通过理解list容器的底层代码,从而加深对list容器的使用的理解。

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

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

相关文章

Vue(七) TodoList案例1.0

文章目录 组件化编码流程(通用)1. 拆分静态组件2. 初始化列表展示动态数据如何让一个标签动态的拥有某一个属性 3. 按回车添加todo子组件给父组件传值之props 4. 勾选与取消勾选一个Todo5. 删除6. footer底部统计7. footer底部交互7.1 全选框自动打勾7.2 全选框取消勾选 8. 清除…

什么是短视频矩阵?一个人能做好短视频矩阵营销吗?

很多人认为做短视频矩阵就是多账号、多发视频就可以了&#xff0c;但其实做短视频矩阵&#xff0c;并不仅仅是更多账号更多视频那么简单&#xff0c;它的核心在于搭建一个全方位的内容传播方式。这种方式包括三个方面&#xff1a;账号矩阵、平台矩阵和内容矩阵。 首先是账号矩阵…

SnailJob:分布式环境设计的任务调度与重试平台!【送源码】

背景 近日挖掘到一款名为“SnailJob”的分布式重试开源项目,它旨在解决微服务架构中常见的重试问题。在微服务大行其道的今天&#xff0c;我们经常需要对某个数据请求进行多次尝试。然而&#xff0c;当遇到网络不稳定、外部服务更新或下游服务负载过高等情况时&#xff0c;请求…

emmc协议

一、简介 1.1 简介 嵌入式多媒体卡&#xff08;Embedded Multimedia Card, eMMC&#xff09;是由 JEDEC 协会所订立&#xff0c;将 MMC controller 和 NAND Flash 封装到一个芯片中&#xff0c;简化存储器的使用和电路板的设计。 1.2 信号 singledescriptionclkclockdata…

【Spring Boot-IDEA创建spring boot项目方法】

1. 使用Spring Initializr 的 Web页面创建项目 2. 使用 IDEA 直接创建项目&#xff0c;其中有两种不同的搭建路径 3. 使用 IDEA 创建Maven项目并改造为springBoot 最常使用的两种方法其实就是一种&#xff0c;这里介绍在ieda中如何搭建 SpringBoot项目。 1.new Project--> 2…

恒电流间歇滴定法 (GITT) 测试教程

文章目录 恒电流间歇滴定法 (GITT) 测试教程1. GITT 测试原理2. 实验准备2.1 设备与材料2.2 配置实验装置 3. GITT 测试步骤3.1 设定测试参数3.2 执行 GITT 测试 4. 数据分析4.1 电压变化分析4.2 扩散系数计算4.3 电荷传输阻抗分析 5. 总结与应用 恒电流间歇滴定法 (GITT) 测试…

Java18 设计模式

第十八节&#xff1a;设计模式 1.设计模式概述 1.1软件设计模式的产生背景 ​ "设计模式"最初并不是出现在软件设计中&#xff0c;而是被用于建筑领域的设计中。1977年美国著名建筑大师、加利福尼亚大学伯克利分校环境结构中心主任克里斯托夫亚历山大&#xff08;…

安卓开发环境搭建1

1、参考地址&#xff1a;Android开发环境搭建_kiba518的博客-CSDN博客 安装jdk 安装Android.Studio 2、就这样&#xff0c;next&#xff0c;搞定安卓开发环境&#xff0c;耗时20分钟 3、参考视频&#xff1a; 三&#xff1a;Android Studio安装_哔哩哔哩_bilibili 1.手机设…

XSS漏洞

本质 变量在接收数据时&#xff0c;数据被写成js脚本&#xff0c;然后进行回显操作&#xff0c;就被浏览器执行&#xff1b;js可以干什么&#xff0c;这个漏洞就可以干什么 产生层面 前端 函数类 echo… 漏洞操作对应层 危害影响 js代码决定 浏览器内核版本 版本是否支持执…

Ubuntu Linux Server安装Kubernetes

本文主要描述在Ubuntu Linux Server操作系统中安装Kubernetes云原生对应的microk8s组件。 sudo snap install microk8s --classic 如上所示&#xff0c;在Ubuntu服务器中安装microk8s组件完成&#xff0c;对应的版本是microk8s v1.30版本 microk8s enable dashboard 如上所…

ISIS路由渗透

/ 实验介绍: / 原理概述 在IS-IS网络中&#xff0c;所有的Level-2和Level-1-2路由器构成了一个连续的骨干区域。Level-1区域必须且只能与骨干区域相连&#xff0c;不同的Level-1区域之间不能直接相连。Level-1区域内的路由信息会通过Level-1-2路由器通报给Level-2区域&#x…

语音测试(二)音频标注

一、标注工具&#xff08;praat&#xff09; Praat的主要功能是对自然语言的语音信号进行采集、分析和标注&#xff0c;并执行包括变换和滤波等在内的多种处理任务。 二、标注教程 音频标注工具&#xff08;praat&#xff09; a.打开praat软件在Praat Objects界面上选择Open选…

【全志H616】【开源】 ARM-Linux 智能分拣项目:阿里云、网络编程、图像识别

【全志H616】【开源】 ARM-Linux 智能分拣项目&#xff1a;阿里云、网络编程、图像识 文章目录 【全志H616】【开源】 ARM-Linux 智能分拣项目&#xff1a;阿里云、网络编程、图像识1、实现功能2、软件及所需环境3、逻辑流程图及简述3.1 完整逻辑流程图3.2 硬件接线3.3 功能简述…

我的sql我做主!Mysql 的集群架构详解之组从复制、半同步模式、MGR、Mysql路由和MHA管理集群组

目录 Mysql 集群技术一、Mysql 在服务器中的部署方法1.1 在Linux下部署mysql1.1.1 安装依赖性&#xff1a;1.1.2 下载并解压源码包1.1.3 源码编译安装mysql1.1.4 部署mysql 二、Mysql的组从复制2.1 配置mastesr2.2 配置salve2.3 当有数据时添加slave22.4 延迟复制2.5 慢查询日志…

wlanapi.dll丢失怎么办?有没有什么靠谱的修复wlanapi.dll方法

在遇到各种系统文件错误当中&#xff0c;其中之一就是“wlanapi.dll文件丢失”的问题。这种问题通常发生在Windows操作系统上&#xff0c;特别是当系统试图执行与无线网络相关的任务时。wlanapi.dll是一个重要的系统文件&#xff0c;它负责处理Windows无线网络服务的许多功能。…

【ESP32 】VScode -window环境配置(adruino开发)(点亮LED)

创建工程 新建工程 、 进行vs code的下载&#xff0c;等待一段时间 工程代码 #include <Arduino.h>// put function declarations here: int myFunction(int, int);void setup() {// put your setup code here, to run once:int result myFunction(2, 3);pinMode(2…

一分钟创建自己的分班查询系统,家长扫码即可进群

开学后&#xff0c;老师们的忙碌也达到了顶峰。整理教材、准备课程计划、布置教室&#xff0c;这些工作已经让人应接不暇&#xff0c;更别提还要处理分班事宜。以往&#xff0c;老师们需要一个个通知家长分班结果&#xff0c;这不仅耗时耗力&#xff0c;还容易出错。家长们也常…

【Qt】tcp服务器、tcp多线程服务器、心跳保持、服务端组包

文章目录 背景&#xff1a;代码实现&#xff08;服务端&#xff09;&#xff1a;总结改进方案&#xff1a;多线程tcp服务器代码实现&#xff08;服务端&#xff09;心跳保持&#xff1a;大文件收发 背景&#xff1a; 局域网内&#xff0c;客户端会进行udp广播&#xff0c;服务…

书法图片自动扣字的批处理

本程序会根据原文字图片&#xff0c;自动扣字并生成黑字、红字2个透明的png图片&#xff0c;原图片黑字或白字均可。运行的话需要先安装好 ImageMagick-7.1.1-37 用法与生成效果举例&#xff1a; a.jpg 白字 转 黑、红扣字png: b.jpg 黑字 转 黑、红扣字png: 分享脚本如下: …

Spring MVC 八股文

目录 重点 SpringMVC的工作原理 Spring MVC 拦截器 Spring MVC 的拦截器和 Filter 过滤器有什么差别&#xff1f; 基础 什么是SpringMVC SpringMVC的优点 Spring MVC的核心组件 Spring MVC的常用注解由有哪些 Controller 注解有什么用 重点 SpringMVC的工作原理 1、客…