初识c++——list
一、list
1、list结构
c++中list为双向带头循环列表:
二、list接口
1、构造
using namespace std;
#include<iostream>
#include<list>
#include<vector>
int main()
{list<int> lt; //构造空的listlist<int> lt1(10, 1); //构造的list中包含n个值为val的元素for (auto& it : lt1){cout << it;}list<int> lt2 = lt1;//拷贝构造函数vector<int>vr(10, 2);list<int> lt3(vr.begin(), vr.end());for (auto& it : lt3){cout << it;}return 0;
}
2、迭代器
注:c++的迭代器不支持+,-操作符
1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
3、空间
using namespace std;
#include<iostream>
#include<list>
#include<vector>
int main()
{list<int> lt; //构造空的listlist<int> lt1(10, 1); //构造的list中包含n个值为val的元素for (auto& it : lt1){cout << it;}list<int> lt2 = lt1;//拷贝构造函数vector<int>vr(10, 2);list<int> lt3(vr.begin(), vr.end());for (auto& it : lt3){cout << it;}if (!lt3.empty()){cout << lt3.size();}return 0;
}
4、节点访问
using namespace std;
#include<iostream>
#include<list>
#include<vector>
int main()
{list<int> lt; //构造空的listlist<int> lt1(10, 1); //构造的list中包含n个值为val的元素for (auto& it : lt1){cout << it;}list<int> lt2 = lt1;//拷贝构造函数vector<int>vr(10, 2);list<int> lt3(vr.begin(), vr.end());for (auto& it : lt3){cout << it;}cout << endl;if (!lt3.empty()){cout << lt3.size() << lt3.front() << lt3.back();}return 0;
}
5、修改元素
using namespace std;
#include<iostream>
#include<list>
#include<vector>
int main()
{list<int> lt1(10, 1); list<int> lt2(10, 2);lt1.push_back(3);//尾插lt1.pop_back();//尾删lt1.push_front(3);//头插lt1.pop_front();//头删lt1.insert(lt1.begin(), 3);//在list position 位置中插入值为val的元素lt1.erase(lt1.begin()); //删除list position位置的元素lt1.swap(lt2);//交换两个list中的元素for (auto& it : lt1){cout << it;}lt1.clear();//清空list中的有效元素for (auto& it : lt1){cout << it;}return 0;
}
三、迭代器失效
我们在平时可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无
效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入
时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭
代器,其他迭代器不会受到影响。
void TestListIterator1()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto it = l.begin();while (it != l.end()){// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值l.erase(it);++it;}
}
// 改正
void TestListIterator()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto it = l.begin();while (it != l.end()){l.erase(it++); // it = l.erase(it);}
}
四、模拟实现
1、构造和析构
void CreateHead()
{_pHead = new Node;_pHead->_pNext = _pHead->_pPre = _pHead;_list_size = 0;
}
list()
{CreateHead();
}list(int n, const T& value = T())
{for (size_t i = 0; i < n; i++){push_back(value);}
}template <class Iterator>
list(Iterator first, Iterator last)
{auto it = first;while (it!=last){push_back(*it);it++;}
}list(const list<T>& l)
{CreateHead();for (auto& e : lt){push_back(e);}
}void swap(list<T>& l)
{std::swap(_pHead, l._pHead);std::swap(_list_size, l._list_size);
}
list<T>& operator=(const list<T> l)
{swap(lt);return *this;
}~list()
{clear();delete _pHead;_pHead = nullptr;
}
2、迭代器
由于list的储存空间不是连续的,所以我们要单独实现++/–等操作,所以我们直接放在一个类中去实现它(但是我们还是用节点指针去实现它,所以成员函数还是节点指针),这里以const_iterator为例子
template<class T>
struct list_const_iterator
{typedef list_node<T> Node;typedef list_const_iterator<T> Self;Node* _node;list_const_iterator(Node* node):_node(node){}const T& operator*(){return _node->_data;}const T* operator->()//这里主要是为了有成员变量也是类的情况{return &_node->_data;}Self& operator++(){_node = _node->_next;return *this;}Self& operator--(){_node = _node->_prev;return *this;}Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}Self& operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}
};
但是这样写太过麻烦,我们看库里面是如何实现的:
template<class T, class Ref, class Ptr>
struct ListIterator
{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;
public:ListIterator(PNode pNode = nullptr):_node(pNode){}T& operator*(){return _node->_val;}T* operator->(){return &_node->_val;}Self& operator++() {_node = _node->_pNext;return *this;}Self& operator++(int){Self tmp(*this);_node = _node->_pNext;return tmp;}Self& operator--(){_node = _node->_pPre;return *this;}Self& operator--(int){Self tmp(*this);_node = _node->_pPre;return tmp;}bool operator!=(const Self& l) const{return _node != l._node;}bool operator==(const Self& l) const{return _node == l._node;}PNode _node;
};iterator begin(){return _pHead->_pNext;//这走隐式类型转化}iterator end(){return _pHead;}const_iterator begin() const{return _pHead->_pNext;}const_iterator end() const{return _pHead;}
这里画个图帮大家理解一下:
3、空间
size_t size()const
{return _list_size;
}
bool empty()const
{return _list_size == 0;
}
4、数据操作
// List Access
T& 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(begin(), val);}void pop_back(){erase(--end());}void push_front(const T& val){insert(end(), val);}void pop_front(){erase(begin());}// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* node = new Node(val);Node* pre = pos._node->_pPre;pre->_pNext = node;pos._node->_pPre = node;node->_pNext = pos._node;node->_pPre = pre;++_list_size;return node;}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(pos != end());//不能释放哨兵位头节点Node* pre = pos._node->_pPre;Node* next = pos._node->_pNext;pre->_pNext = next;next->_pPre = pre;delete pos._node;--_list_size;return next;}void clear(){auto it = begin();while (it != end()){it = erase(it);}_list_size = 0;}
这里唯一要注意不能删除哨兵位的节点,这样会导致无法访问该list(begin,end都和l哨兵位有关),所以erase不能删除end的节点(end指向的就是哨兵位节点)
5、总文件
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace lt
{// List的节点类template<class T>struct ListNode{ListNode(const T& val = T()):_val(val),_pPre(nullptr),_pNext(nullptr){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};//List的迭代器类template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;public:ListIterator(PNode pNode = nullptr):_node(pNode){}T& operator*(){return _node->_val;}T* operator->(){return &_node->_val;}Self& operator++() {_node = _node->_pNext;return *this;}Self& operator++(int){Self tmp(*this);_node = _node->_pNext;return tmp;}Self& operator--(){_node = _node->_pPre;return *this;}Self& operator--(int){Self tmp(*this);_node = _node->_pPre;return tmp;}bool operator!=(const Self& l) const{return _node != l._node;}bool operator==(const Self& l) const{return _node == l._node;}PNode _node;};//list类template<class T>class list{typedef ListNode<T> Node;public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;public:///// List的构造list(const T& value = T()){CreateHead();}list(int n, const T& value = T()){for (size_t i = 0; i < n; i++){push_back(value);}}template <class Iterator>list(Iterator first, Iterator last){auto it = first;while (it!=last){push_back(*it);it++;}}list(const list<T>& l){CreateHead();for (auto& e : lt){push_back(e);}}list<T>& operator=(const list<T> l){swap(lt);return *this;}~list(){clear();delete _pHead;_pHead = nullptr;}///// List Iteratoriterator begin(){return _pHead->_pNext;//这走隐式类型转化}iterator end(){return _pHead;}const_iterator begin() const{return _pHead->_pNext;}const_iterator end() const{return _pHead;}///// List Capacitysize_t size()const{return _list_size;}bool empty()const{return _list_size == 0;}// 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(begin(), val);}void pop_back(){erase(--end());}void push_front(const T& val){insert(end(), val);}void pop_front(){erase(begin());}// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* node = new Node(val);Node* pre = pos._node->_pPre;pre->_pNext = node;pos._node->_pPre = node;node->_pNext = pos._node;node->_pPre = pre;++_list_size;return node;}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(pos != end());//不能释放哨兵位头节点Node* pre = pos._node->_pPre;Node* next = pos._node->_pNext;pre->_pNext = next;next->_pPre = pre;delete pos._node;--_list_size;return next;}void clear(){auto it = begin();while (it != end()){it = erase(it);}_list_size = 0;}void swap(list<T>& l){std::swap(_pHead, l._pHead);std::swap(_list_size, l._list_size);}private:void CreateHead(){_pHead = new Node;_pHead->_pNext = _pHead->_pPre = _pHead;_list_size = 0;}Node* _pHead;size_t _list_size = 0;};
}
五、list和vector的对比
相关文章:

初识c++——list
一、list 1、list结构 c中list为双向带头循环列表: 二、list接口 1、构造 using namespace std; #include<iostream> #include<list> #include<vector> int main() {list<int> lt; //构造空的listlist<int> lt1(10, 1); //构造的l…...

angular入门基础教程(八)表单之双向绑定
绑定表单数据 为了让表单使用 Angular 的特性实现数据绑定,需要导入 FormsModule。 这个比 vue 要繁琐点,不复杂,但是比 react 的自己手动实现要方便,ng 帮我们实现了双向绑定 import { Component } from "angular/core&qu…...
【C++】C++中的find方法介绍
目录 一.find方法基本用法 1.查找字符 2.查找子字符串 3.查找子字符串(从指定位置开始) 4.查找字符范围 5.查找不包含特定字符的范围 二.使用string::npos返回无效位置 三.总结 在C中, std::string 类的 find 成员函数用于查找子字…...

JVM—HotSpot虚拟机对象探秘
1、对象的创建 对象只是普通对象,不包括数组和Class对象 类加载检查:当虚拟机遇到字节码New指令时,先检查这个指令的参数是否可以在常量池定位到一个类的符号引用,并且加载这个符号引用代表的类是否被加载、解析、验证、初始化过。…...

AI测试:人工智能模型的核心测试指标,分类判别、目标检测、图像分割、定量计算分别有哪些指标?
在前面的人工智能测试技术系列文章中,我们详细介绍了人工智能测试的技术方法和实践流程。在了解人工智能测试方法后,我们需要进一步学习和研究如何衡量这些方法的有效性,即人工智能模型测试指标的选择。测试指标的选择主要取决于模型的类型和…...

探索LLM世界:新手小白的学习路线图
随着人工智能的发展,语言模型(Language Models, LLM)在自然语言处理(NLP)领域的应用越来越广泛。对于新手小白来说,学习LLM不仅能提升技术水平,还能为职业发展带来巨大的机遇。那么,…...
Linux基础命令大全 持续更新中......
最近重新学习了linux基础知识,并整理出了以下内容,以供参考 最近几日后续会持续更新内容哦 用户管理 加括号的代表可以不写 useradd (参数选项) 用户名 添加新用户 passwd (参数选项) 用户名 用…...
CPU的起源与发展历程
CPU的起源与发展历程 文章目录 CPU的起源与发展历程前言指令概念电子管(真空管)体系结构冯诺依曼架构哈佛架构 晶体管集成电路指令集与微架构微处理器x86架构CISC与RISC的提出MIPS架构ARM架构RISC-V架构FPGA 总结 前言 从古至今,人类为了…...

【C语言】 二叉树创建(结构体,先序遍历,中序遍历,后续遍历)
二叉树的创建:首先先定义一个结构体,里面包含数据(data),指向左子树的指针(L),指向右子树的指针(R)三个部分 在创建树的函数中,首先先输入…...

【和相同的二元子数组】python刷题记录
R2-前缀和专题 目录 前缀和哈希表 双指针 ps: 第一眼过去,这题应该能用双指针解出来,应该也能用前缀和解题。 前缀和哈希表 适用于 nums[i] 值不固定为 0 和 1 的其他情况 class Solution:def numSubarraysWithSum(self, nums: List[int], goal: i…...

【单片机毕业设计选题24087】-基于北斗系统的智能路灯
系统功能: 系统操作说明: 上电后OLED显示 “欢迎使用智能路灯系统请稍后”,两秒后显示Connecting...表示 正在连接阿里云,正常连接阿里云后显示第一页面,如长时间显示Connecting...请 检查WiFi网络是否正确。 系统分为四种模…...
[Docker][Docker常用命令]详细讲解
目录 1.帮助命令2.镜像命令3.容器命令4.卷命令5.常用命令 1.帮助命令 docker version # 显示docker的版本信息 docker info # 显示docker的系统信息,包括镜像和容器的数量 docker 命令 --help # 某条命令的帮助命令2.镜像命令 查看所有本地的主机上的镜像…...

onlyoffice用nginx反向代理
我对于onlyoffice的需求就是当个在线编辑器使用。在集成react的时候之前都是写的绝对路径的地址,这样在需要迁移应用的时候就造成了巨大的麻烦,所以我决定用nginx做反向代理,这样我集成的时候就不用每次都修改源码中的地址了。 一开始写的代…...
JavaScript字符串转换成base64编码方法
// base64编码表 const base64EncodeChars ref<string>("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/" );/*** base64编码* param {Object} str*/ const base64encode (str: string) > {let result "";// 循环遍历字符串…...

25.惰性队列
介绍 消费者由于各种原因而致使长时间不能消费消息造成堆积。比如有一百万条消息发送到mq中,消费者这时宕机了不能消费消息,造成了消息堆积。惰性队列就有必要了。 正常情况下,消息保存在内存中。消费者从内存中读取消息消费,速…...

ControlNet on Stable Diffusion
ControlNet on Stable Diffusion 笔记来源: 1.Adding Conditional Control to Text-to-Image Diffusion Models 2.How to Use OpenPose & ControlNet in Stable Diffusion 3.ControlNet与DreamBooth:生成模型的精细控制与主体保持 4.Introduction t…...

源码编译安装,及nginx服务控制、监控块
1.源码编译安装: [root17dns ~]# wget https://nginx.org/download/nginx-1.27.0.tar.gz 2.解压: [root17dns ~]# tar -zxvf nginx-1.27.0.tar.gz 3.安装gcc等工具 [root17dns ~]# yum -y install gcc gcc-c [root17dns ~]# yum -y install make lrzsz …...
在react中使用wangeditor富文本
官方文档 wangeditor5在线文档 依赖安装(react框架) yarn add wangeditor/editor # 或者 npm install wangeditor/editor --saveyarn add wangeditor/editor-for-react # 或者 npm install wangeditor/editor-for-react --save在React 中使用wangEditor …...

拉提查合创5步玩转git工具协作代码开发
1 工具使用场景 开发团队使用git版本管理工具,进行协作代码开发过程中,最常用的场景为: (1)拉取代码 将git远端仓库最新代码拉取到本地。 (2)提交代码 将本地新增修改的代码提交至git远端仓库中…...
React特点
React 是一个用于构建用户界面的 JavaScript 库,由 Facebook 开发并维护。React 的特点主要体现在以下几个方面: 声明式(Declarative):React 使你能够以一种声明的方式来描述你的 UI,这使得代码更加容易理解…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...