C++ : list类及其模拟实现

目录

一、list的介绍和使用

list的介绍

list的使用

1.list的构造

构造函数

2.list iterator 的使用

3.list capacity

4.list element access

5.list modifiers

6.list的迭代器失效

二、list的模拟实现

要点

list类模拟实现部分接口全部代码展示


一、list的介绍和使用

list的介绍

1.list 是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。

2.list的底层是带头双向可循环链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

3.list和forward_list非常相似:最主要的不同在于forward_list 是单链表,只能朝前迭代,让其更简单高效。

4.与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。

5.与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间。

list的使用

1.list的构造

构造函数

(1)是指传来一个空指针,构造空的list

(2)指构造n个值为val的list

(3)用[first,last)中的元素构造list

(4)用x链表拷贝构造

2.list iterator 的使用

迭代器可以理解成一个指针,因为它封装了底层的逻辑,像指针一样使用。该指针指向list中的某个节点。begin就是指向第一个节点(非哨兵),end,返回最后一个元素下一个位置(就是哨兵位)。rbegin返回end位置,rend,返回begin位置。

注意:

begin和end是正向迭代器,对迭代器++,迭代器向后移动

rbegin和rend是反向迭代器,对迭代器++,迭代器向前移动

3.list capacity

empty 检查list是否是空链表

size  返回list中有效节点个数

4.list element access

front 返回list中,第一个节点的值的引用

back返回list中,最后一个节点的值的引用

5.list modifiers

模拟实现的话,掌握红框中常用的就好。

push_front 在list首节点前插入 值为val的节点

pop_front 删除list首节点

push_back 在list最后一个元素后插入值为val的节点

pop_back 删除list尾结点

insert 在pos位置插入一个值为val的节点

erase 删除pos位置的节点

swap  交换两个list中的元素

clear 清除list中的有效节点

6.list的迭代器失效

迭代器失效是指迭代器指向的节点无效,也就是该节点被删除了,用户不会再有该节点的访问权限。因为list的底层是带头双向循环链表,所以在list中进行插入时是不会导致list迭代器失效的,只有在删除时才会失效,并且失效的只有被删除节点的迭代器,其他节点的迭代器不会受到影响。

在逐个(调用erase函数时,参数)用后置++,不用前置++。表示删除以后,it又被重新赋值了。

二、list的模拟实现

要点

1.list要实现节点链表还有迭代器三个部分,分别建立三个类模板。这是为了提高类的复用性。封装在自己的命名空间里。

2.单个节点的结构体是公有的开放的,因为要在其他类里经常调用。所以得开放。包含val,前指针和后指针,以及构造函数。

 // List的节点类template<class T>struct ListNode{ListNode(const T& val = T()):_pPre(nullptr), _pNext(nullptr), _val(val){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};

3.写迭代器的类时,迭代器指针也要设置为开放的,为了后面在list类中erase  pos位置和insert pos位置可以访问。迭代器的类模板是这样的。

Ref 和Ptr分别是迭代器返回的引用类型  和 迭代器返回的指针类型。

如果写T& 和T*,会限制迭代器返回的类型,这样想要返回const T& 和const T* 也无法更改。而Ref可以使你在实例化的时候就可以选择返回类型是什么。

//List的迭代器类
template<class T, class Ref, class Ptr>
class ListIterator
{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;//加了Ref和Ptr后,代码的灵活性提高
public:                                 //体现在返回的时候和实例化的时候,我可以控制迭代器解引 //用后返回什么类型ListIterator(PNode pNode = nullptr):_pNode(pNode){}ListIterator(const Self& l):_pNode(l._pNode){}Ref operator*(){return _pNode->_val;}Ptr operator->(){return &_pNode->_val;}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){Self ptmp(*this);_pNode = _pNode->_pNext;return ptmp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){Self ptmp(*this);_pNode = _pNode->_pPre;return ptmp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return _pNode == l._pNode;}
public:PNode _pNode;
};

list类模拟实现部分接口全部代码展示

#pragma once
#include<iostream>
#include <assert.h>
using namespace std;namespace ting
{// List的节点类template<class T>struct ListNode{ListNode(const T& val = T()):_pPre(nullptr), _pNext(nullptr), _val(val){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};//List的迭代器类template<class T, class Ref, class Ptr>class ListIterator{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;//加了Ref和Ptr后,代码的灵活性提高public:                                 //体现在返回的时候和实例化的时候,我可以控制迭代器解引用后返回什么类型ListIterator(PNode pNode = nullptr):_pNode(pNode){}ListIterator(const Self& l):_pNode(l._pNode){}Ref operator*(){return _pNode->_val;}Ptr operator->(){return &_pNode->_val;}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){Self ptmp(*this);_pNode = _pNode->_pNext;return ptmp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){Self ptmp(*this);_pNode = _pNode->_pPre;return ptmp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return _pNode == l._pNode;}public:PNode _pNode;};//list类template<class T>class list{typedef ListNode<T> Node;typedef Node* PNode;public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;public:///// List的构造list(){//处理私设的变量CreateHead();}list(int n, const T& value = T()){CreateHead();while (n--){push_back(value);}}template <class Iterator>list(Iterator first, Iterator last){CreateHead();while (first != last){push_back(*first);++first;}}list(const list<T>& l){CreateHead();list<T> tmp(l.begin(), l.end());swap(tmp);}list<T>& operator=(const list<T> l){swap(l);return *this;}~list(){clear();delete _pHead;_pHead = nullptr;}///// List Iteratoriterator begin(){return iterator(_pHead->_pNext);//因为_pNext不是迭代器类型,要走迭代器的拷贝构造}iterator end(){return iterator(_pHead);}const_iterator begin() const{return const_iterator(_pHead->_pNext);}const_iterator end() const{return const_iterator(_pHead);}///// List Capacitysize_t size()const{size_t n = 0;for (auto it = begin(); it != end(); ++it){++n;}return n;}bool empty()const{return _pHead->_pNext == _pHead;}// List AccessT& front(){return _pHead->_pNext->_val;}const T& front()const{return _pHead->_pNext->_val;}T& back(){return _pHead->_pPre->_val;}const T& back()const{return _pHead->_pPre->val;}// List Modifyvoid 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()); }// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){PNode newnode = new Node(val);newnode->_pNext = pos._pNode;newnode->_pPre = pos._pNode->_pPre;newnode->_pPre->_pNext = newnode;pos._pNode->_pPre = newnode;return iterator(newnode);}iterator erase(iterator pos){assert(pos != end());PNode nextNode = pos._pNode->_pNext;pos._pNode->_pPre->_pNext = pos._pNode->_pNext;pos._pNode->_pNext->_pPre = pos._pNode->_pPre;delete pos._pNode;return iterator(nextNode);}void clear(){while (!empty()){pop_back();}}void swap(list<T>& l){std::swap(_pHead, l._pHead);}private:void CreateHead(){_pHead = new Node();_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;}PNode _pHead;};
};

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

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

相关文章

Docker:centos7安装docker

官网&#xff1a;https://www.docker.com/官网 文档地址 - 确认centos7及其以上的版本 查看当前系统版本 cat /etc/redhat-release- 卸载旧版本 依照官网执行 - yum安装gcc相关 yum -y install gccyum -y install gcc-c- 安装需要的软件包 yum install -y yum-utils- 设置s…

深入学习Linux内核页框回收

目录 算法 1.选择目标页 2.PFRA设计 3.反向映射 3.1.匿名页的反向映射 3.2.try_to_unmap_anon()函数 3.3.try_to_unmap_one()函数 映射页的反向映射 优先搜索树 try_to_unmap_file()函数 PFRA实现 最近最少使用(LRU)链表 在LRU链表之间移动页 mark_page_accessed(…

Android使用kts发布aar到JitPack仓库

Android使用kts发布aar到JitPack 之前做过sdk开发&#xff0c;需要将仓库上传到maven、JitPack或JCenter,但是JCenter已停止维护&#xff0c;本文是讲解上传到JitPack的方式,使用KTS语法&#xff0c;记录使用过程中遇到的一些坑.相信Groovy的方式是大家经常使用的&#xff0c;…

Java基于Spring Boot框架的课程管理系统(附源码,说明文档)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

基于Springboot的校园疫情防控系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园疫情防控系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

C# WCF服务(由于内部错误,服务器无法处理该请求。)

由于内部错误&#xff0c;服务器无法处理该请求。有关该错误的详细信息&#xff0c;请打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribute 或从 <serviceDebug> 配置行为)以便将异常信息发送回客户端&#xff0c;或打开对每个 Microsoft .NET …

从零开始:Django项目的创建与配置指南

title: 从零开始&#xff1a;Django项目的创建与配置指南 date: 2024/5/2 18:29:33 updated: 2024/5/2 18:29:33 categories: 后端开发 tags: DjangoWebDevPythonORMSecurityDeploymentOptimization Django简介&#xff1a; Django是一个开源的高级Python Web框架&#xff…

抖音直播怎么赚钱的?有多少种方法?

抖音直播确实很能挣钱&#xff0c;它一般有两种方式赚钱&#xff0c;一种是靠粉丝打赏赚钱&#xff0c;一种是在直播间卖货赚钱&#xff01; 1、抖音直播的赚钱方法一&#xff1a;粉丝打赏 主播在抖音直播&#xff0c;首先的收入来源就是靠粉丝的打赏&#xff0c;粉丝打赏的礼…

C语言之整形提升和算术转换

目录 前言 一、整形提升 二、算术转换 总结 前言 本文主要介绍C语言中的整形提升和算术转换的概念和意义&#xff0c;以及例题帮助理解&#xff0c;了解之后&#xff0c;我们就能知道在C语言中&#xff0c;字符型变量如何计算以及如果变量的类型、字节大小不一致的情况下&am…

2012NOIP普及组真题 4. 文化之旅

线上OJ&#xff1a; 一本通&#xff1a;http://ybt.ssoier.cn:8088/problem_show.php?pid1960 相似题目&#xff1a; 本题和 2017年 NOIP J 组第3题 棋盘 类似。 核心思想&#xff1a; 由于本题的数据范围 n ≤ 100,非常小&#xff0c;所以可以采用 深搜 dfs 进行。同时&am…

C++程序设计:new和malloc的区别

new和malloc的区别 1.用法和语法2.类型安全性3.初始化4.分配数组5.异常处理示例代码 1.用法和语法 new 是 C 中的运算符&#xff0c;而 malloc 是 C 语言中的函数。new 用于动态分配单个对象或数组&#xff0c;并且在分配内存后调用对象的构造函数进行初始化。malloc 用于动态分…

golang学习笔记(内存模型和分配机制)

操作系统的存储管理 虚拟内存管理 虚拟内存是一种内存管理技术&#xff0c;它允许操作系统为每个进程提供一个比实际物理内存更大的地址空间。这个地址空间被称为虚拟地址空间&#xff0c;而实际的物理内存则被称为物理地址空间。使用虚拟内存有以下几点好处&#xff1a; 内…

C# 用户控件UserControl事件解绑资源释放

用户控件继承子 UserControl 。 现在有个业务需求在UserControl 所在的窗体关闭时解除事件HMouseDown绑定。 因没有相关的Close事件。后来本人想了一个办法在 ROICtlDesigner类的 Dispose 方法中执行相关的释放代码 比如解除事件绑定 释放资源 public partial class ROICt…

git 第一次安装设置用户名密码

git config --global user.name ljq git config --global user.email 15137659164qq.com创建公钥命令 输入后一直回车 ssh-keygen -t rsa下面这样代表成功 这里是公钥的 信息输入gitee 中 输入下面命令看是否和本机绑定成功 ssh -T gitgitee.com如何是这样&#xff0c;恭喜…

Ubuntu系统重装

1、删除相关卷&#xff0c;ubuntu引导项&#xff08;select disk、assign letter的方法&#xff09; Ubuntu20.04重装系统过程&#xff08;多图&#xff0c;含保存文件卸载旧系统安装新系统&#xff09;_ubuntu重装系统-CSDN博客 2、分配空间 efi 1024MB 逻辑分区 swap 8*1…

基于51单片机PWM控制直流电机—数码管显示

基于51单片机PWM控制直流电机 &#xff08;仿真&#xff0b;程序&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1.L298驱动直流电机&#xff1b; 2.数码管显示转动方向和PWM占空比&#xff08;0-100%&#xff09;&#xff1b; 3.按键控制PWM占空比来加/…

20232803 2023-2024-2 《网络攻防实践》实践八报告

目录 1. 实践内容2. 实践过程2.1 动手实践任务一2.2 动手实践任务二&#xff1a;分析Crackme程序2.2.1 crackme1.exe2.2.2 crackme2.exe 2.3 分析实践任务一2.4 分析实践任务二 3. 学习中遇到的问题及解决4. 学习感悟、思考等 1. 实践内容 动手实践任务一&#xff1a;对提供的r…

Vue入门到关门之第三方框架elementui

1、什么是ElementUI&#xff1f; Element UI 是一个基于 Vue.js 的组件库&#xff0c;它提供了丰富的 UI 组件和一套完整的解决方案&#xff0c;用于快速构建现代化的 Web 应用程序。Element UI 的目标是帮助开发者快速构建出美观、易用的界面&#xff0c;并提供了丰富的组件&…

四种粒子群算法的Matlab实现

粒子群算法&#xff0c;又称为粒子群优化&#xff08;Particle Swarm Optimization&#xff0c;简称PSO&#xff09;&#xff0c;是一种基于群体智能的优化算法。它最初由James Kennedy和Russell Eberhart于1995年提出&#xff0c;灵感来源于鸟群捕食行为的研究。在PSO中&#…

R语言实战——中国职工平均工资的变化分析——相关与回归分析

链接: R语言学习—1—将数据框中某一列数据改成行名 R语言学习—2—安德鲁斯曲线分析时间序列数据 R语言学习—3—基本操作 R语言学习—4—数据矩阵及R表示 R语言的学习—5—多元数据直观表示 R语言学习—6—多元相关与回归分析 1、源数据 各行业平均工资变化 各地区平均工资…