初识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,这使得代码更加容易理解…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...
PydanticAI快速入门示例
参考链接:https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...
GAN模式奔溃的探讨论文综述(一)
简介 简介:今天带来一篇关于GAN的,对于模式奔溃的一个探讨的一个问题,帮助大家更好的解决训练中遇到的一个难题。 论文题目:An in-depth review and analysis of mode collapse in GAN 期刊:Machine Learning 链接:...
