C++----剖析list

前面学习了vector和string,接下来剖析stl中的list,在数据库中学习过,list逻辑上是连续的,但是存储中是分散的,这是与vector这种数组类型不同的地方。所以list中的元素设置为一个结构体,将list设计成双向的:

	template <class T>struct list_node{list_node<T>* _next;list_node<T>* _pre;T _data;list_node(const T& val=T()):_next(nullptr),_pre(nullptr),_data(val){}};

接下来是stl中的迭代器部分,list的迭代器还可以像vector这种原生指针是的使用方式使用吗?答案是否定的,因为vector的底层存储是连续的,并且迭代器就是vector内部元素指针的简单封装。所以底层自然实现起来比较简单,但是list的底层不可以,比如迭代器++,vector本来就是连续的,所以直接就能用,但是struct不是连续的,所以要自己实现,否则谁知道会++到哪里造成访问未知空间。所以既然它不支持我们直接使用,那我们就造一个迭代器出来,这个迭代器的核心就是node:

	template <class T, class PTR, class PEF>struct _list_iterator{typedef list_node<T> Node;typedef _list_iterator<T,PTR,PEF> self;Node* _node;//核心_list_iterator(Node* node):_node(node){}PEF operator*(){return _node->_data;}//要可以返回值、还能修改!PTR operator->(){return &(operator*());}self& operator++(){_node = _node->_next;return *this;}//后置++self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_pre;return *this;}//后置--self operator--(int){self tmp(*this);_node = _node->_pre;return tmp;}bool operator!=(const self& it){return _node != it._node;}bool operator==(const self& it){return _node == it._node;}};

这里其他的地方没有太大的疑问,就是operator->发现了,返回的是nodedata的地址,首先咱们来看,当T是内置类型int时,是没有必要用这个的吧?直接*就可以得到,但是如果T时自定义类型的呢?比如:

	struct A{int _a;int _b;A(int a = 1,int b=1):_a(a),_b(b){}};void test2(){list<A> l;l.push_back(A(1,1));l.push_back(A(2, 2));l.push_back(A(3, 3));l.push_back(A(4, 4));std::cout << it->_a << " " << it->_b << " ";list<A>::iterator it = l.begin();}

此时我想访问A中的数据,我当然可以重载<<这个运算符了,但是在stl中我们不知道自定义类型中会有什么数据,所以stl中是不会预先,也不能写出来<<运算符。所以就有了->符,我们可以自己访问struct中的数据,但是还有一个问题,->返回struct的地址,还应该再来一个->吧,就是it->->_a,这里编译器做了优化,所以只需要一个->就可以。

看list:

	template <class T>class list{typedef list_node<T> Node;public:typedef _list_iterator<T,T*,T&> iterator;typedef _list_iterator<T,const T*,const T&> const_iterator;iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}list(){_head = new Node;_head->_next = _head;_head->_pre = _head;}//void push_back(Node newnode)//{//	Node* tail = _head->_pre;//	tail->_next = newnode;//	newnode->_pre = tail;//	newnode->_next = _head;//	_head->_pre = newnode;//}void push_back(const T& val){Node* newnode = new Node(val);Node* tail = _head->_pre;tail->_next = newnode;newnode->_pre = tail;newnode->_next = _head;_head->_pre = newnode;}private:Node* _head;};

list的形式:带哨兵位的双向列表

解释模板在const迭代器和普通迭代器中的巧妙使用,通过模板避免多写代码:

 巧妙使用模板参数。

list迭代器失效的场景只存在于删除结点时,他不像vector这种连续的,插入了会导致其中大部分元素发生移动,所以只会在删除结点时,如何解决?返回删除结点的下一个节点的迭代器。

附全部代码:

	template <class T>struct list_node{list_node<T>* _next;list_node<T>* _pre;T _data;list_node(const T& val=T()):_next(nullptr),_pre(nullptr),_data(val){}};template <class T, class PTR, class PEF>struct _list_iterator{typedef list_node<T> Node;typedef _list_iterator<T,PTR,PEF> self;Node* _node;//核心_list_iterator(Node* node):_node(node){}PEF operator*(){return _node->_data;}//要可以返回值、还能修改!PTR operator->(){return &(operator*());}self& operator++(){_node = _node->_next;return *this;}//后置++self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_pre;return *this;}//后置--self operator--(int){self tmp(*this);_node = _node->_pre;return tmp;}bool operator!=(const self& it){return _node != it._node;}bool operator==(const self& it){return _node == it._node;}};template <class T>class list{typedef list_node<T> Node;public:typedef _list_iterator<T,T*,T&> iterator;typedef _list_iterator<T,const T*,const T&> const_iterator;iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}list(){_head = new Node;_head->_next = _head;_head->_pre = _head;}void empty_init(){_head = new Node;_head->_next = _head;_head->_pre = _head;}template<class InputIterator>list(InputIterator first, InputIterator last){empty_init();while (first != last){push_back(*first);++first;}}~list(){clear();delete _head;_head = nullptr;} void swap(list<T>& l){std::swap(_head, l._head);}list(const list<T>& l){ empty_init();list<T> tmp(l.begin(), l.end());swap(tmp);}//l2=l1 list<T>& operator=(list<T> l){swap(l);return *this;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}//void push_back(Node newnode)//{//	Node* tail = _head->_pre;//	tail->_next = newnode;//	newnode->_pre = tail;//	newnode->_next = _head;//	_head->_pre = newnode;//}void insert(iterator pos, const T& val){Node* newnode = new Node(val);Node* cur = pos._node;Node* pre = cur->_pre;cur->_pre = newnode;newnode->_next = cur;pre->_next = newnode;newnode->_pre = pre;}void push_front(const T& val){insert(begin(),val);}void push_back(const T& val){Node* newnode = new Node(val);Node* tail = _head->_pre;tail->_next = newnode;newnode->_pre = tail;newnode->_next = _head;_head->_pre = newnode;}//返回值是删去节点的下一个节点的迭代器,避免迭代器失效,//因为释放了当前迭代器的结点,再次访问会出现错误iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* pre = cur->_pre;Node* next = cur->_next;next->_pre = pre;pre->_next = next;delete cur;return iterator(next);}void pop_front(){iterator it = erase(begin());}void pop_back(){iterator it = erase(--end());}private:Node* _head;};

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

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

相关文章

为什么已经有 Nginx 了,还需要服务网关?

在当前微服务架构中&#xff0c;虽然 Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;但在实际使用中仍然存在诸多局限性。为了满足运维效率、功能统一治理以及与微服务生态集成的需求&#xff0c;通常会在 Nginx 和业务服务之间引入一层基于 Java 实现的服务网关&a…

Kendo UI 中,ViewModel、DataSource 和 Grid的关系。Kendo 框架发起 HTTP 请求

Kendo UI 中&#xff0c;ViewModel、DataSource 和 Grid的关系 在 Kendo UI 中&#xff0c;ViewModel、DataSource 和 Grid 是构建动态数据应用的核心组件&#xff0c;三者协同工作实现数据的绑定、管理和展示。 一、三者关系图解 #mermaid-svg-3lWxu2zWB23wDYEz {font-family…

宇树开源 Qmini 双足机器人,可通过 3D 打印动手制作,使用树莓派作为主控制器

Unitree Qmini 是一款由宇树科技设计并开源的低成本双足机器人&#xff0c;开发者可以完全通过 3D 打印进行复刻。Qmini 专为业余爱好者、教育工作者和研究人员设计&#xff0c;使用户能够快速上手&#xff0c;并以类似乐高的模块化方式组装自己的机器人。该项目为机器人技术提…

解决华为云服务器无法ping通github问题

在push代码到github上的时候&#xff0c;发现显示22端口无法连接&#xff0c;在已经开放了端口&#xff0c;防火墙关闭的情况下仍然无法连接到GitHub。 发现是服务器和github断连&#xff0c;选择 sudo vim /etc/hosts 添加一下代码 # GitHub Start140.82.121.4 gith…

关于electron-vite koffi 读取 dll 打包等问题得记录

koffi const koffi require(‘koffi’) import iconv from ‘iconv-lite’;const libPath path.resolve(__dirname, ‘…/…/resources/dll/sss.dll’) const yktLib koffi.load(libPath) const ret yktLib.func(‘string sss(string Url, string Data, string OutData)’…

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…

通过关键字批量抓取淘宝商品数据实现方法途径分享--API

item_search 按关键字搜索淘宝商品item_search_tmall 按关键字搜索天猫商品item_search_pro 高级关键字搜索淘宝商品item_search_img 按图搜索淘宝商品&#xff08;拍立淘&#xff09;item_search_shop 获得店铺的所有商品 一、引言 在电商领域&#xff0c;获取淘宝商品数据对…

用 Lazarus IDE 写一个邮件客户端软件,能收发邮件,编写邮件

下面是一个使用Lazarus IDE开发的基本邮件客户端实现方案&#xff0c;包含收发邮件和编写邮件的核心功能。我们将使用Synapse库&#xff08;跨平台的网络通信库&#xff09;来处理邮件协议。 步骤1&#xff1a;安装依赖 安装Synapse库&#xff1a; 下载地址&#xff1a;https:…

第二部分-IP及子网划分

目录 一、什么是IP? 1.1.IP地址的由来 1.2.IP地址的表示 1.3.IP地址的构成 1.4.IP地址的分类 1.5.IP地址类型 1.6.IP地址的计算 1.7.私网IP地址 1.8.特殊IP地址 二、子网划分 2.1.什么是子网划分及为什么要进行子网划分? 2.2.如何进行子网划分&#xff1f; 实例&#xff1a; …

【javascript】泡泡龙游戏中反弹和查找匹配算法

引言 泡泡龙游戏的核心玩法依赖于物理碰撞与颜色匹配的算法实现。反弹效果需要模拟泡泡与边界或障碍物的弹性碰撞&#xff0c;确保轨迹符合物理规律&#xff1b;匹配算法则需快速检测相邻同色泡泡&#xff0c;触发消除逻辑。高效的处理方式直接影响游戏流畅度和玩家体验。 以…

如何使用deepseek满血版

deepseek 访问方式 DeepSeek满血版可通过官方网站或官方应用商店下载安装。确保设备满足最低系统要求&#xff0c;如操作系统版本和硬件配置。 账号注册与登录 访问平台后完成账号注册流程&#xff0c;提供必要信息并验证邮箱或手机号。登录后进入用户中心&#xff0c;查看…

网络管理【Linux/Unix/Windows】命令大全

在跨平台网络运维中&#xff0c;管理员常需快速切换Windows与Linux环境下的命令操作。本文整合了核心网络管理命令的跨平台对照表&#xff0c;涵盖连通性测试、路由追踪、DNS解析、ARP管理、会话监控等高频场景。无论您负责服务器维护、网络排障还是安全审计&#xff0c;此表可…

Gremlin创建schema(包括实体和关系)

1、构建图谱schema&#xff0c;流程包括图创建、实体构建以及关系构建。 创建图时需要指定图库名称以及主键字段。 实体构建时需要指定主键字段&#xff0c;每个属性需要指定数据类型&#xff0c;是否非空以及默认值。关系构建时需要包括关系名称、指向头实体的标签&#xff0c…

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG

TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码&#xff1a;HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…

鸿蒙Next仓颉语言开发实战教程:店铺详情页

各位好&#xff0c;幽蓝君又来分享仓颉开发教程了&#xff0c;今天的内容是店铺详情页&#xff1a; 这个页面的内容看似简单&#xff0c;其实有很多小细节需要注意&#xff0c;主要还是让大家熟悉List容器的使用。 整个页面由导航栏和List容器两大部分组成&#xff0c;导航栏我…

FEMFAT许可使用数据分析工具介绍

在高度竞争和快速变化的工程仿真领域&#xff0c;数据驱动的决策变得越来越重要。为了更好地了解FEMFAT许可的使用情况、提高资源利用率、优化工作流程&#xff0c;FEMFAT许可使用数据分析工具应运而生。本文将为您介绍这款强大的工具&#xff0c;助您轻松驾驭FEMFAT许可数据&a…

大模型原理面试题及参考答案

目录 什么是大语言模型(LLM)?它与传统语言模型的本质差异在哪里? 自回归模型(autoregressive)与掩码语言模型(masked LM)的异同是什么?各适合于哪些任务? Transformer 的核心构件——多头自注意力机制如何捕捉长距离依赖? 位置编码(positional encoding)的作用…

Gartner<Reference Architecture Brief: Data Integration>学习心得

数据集成参考架构解析 引言 在当今数字化时代,数据已成为企业最宝贵的资产之一。随着企业规模的不断扩大和业务的日益复杂,数据来源也变得多样化,包括客户关系管理(CRM)、企业资源规划(ERP)、人力资源管理(HR)和市场营销等领域的运营系统。这些系统虽然在其特定功能…

JAVASE:方法

JavaSE 方法详解 一、方法的核心概念 方法&#xff08;Method&#xff09;是一组执行特定任务的语句集合&#xff0c;它将代码逻辑封装为可复用的单元&#xff0c;提高代码的模块化和可维护性。 方法的组成&#xff1a; [修饰符] 返回类型 方法名([参数列表]) {// 方法体[r…

MXNet-cu101 + CUDA 10.1 在 Windows 11 上启用 GPU 的完整指南

一、报错信息 (pytorch) C:\Users\Administrator\Desktop\test>D:/conda/anaconda3/envs/pytorch/python.exe c:/Users/Administrator/Desktop/test/test.py Traceback (most recent call last): File “c:/Users/Administrator/Desktop/test/test.py”, line 1, in import…