当前位置: 首页 > article >正文

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;};

相关文章:

C++----剖析list

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

纳米AI搜索与百度AI搜、豆包的核心差异解析

一、技术定位与设计目标 1、纳米AI搜索&#xff1a;轻量化边缘计算导向
专注于实时数据处理与资源受限环境下的高效响应&#xff0c;通过算法优化和模型压缩技术&#xff0c;实现在物联网设备、智能终端等低功耗场景的本地化部署。其核心优势在于减少云端依赖&#xff0c;保障…...

不到 2 个月,OpenAI 火速用 Rust 重写 AI 编程工具。尤雨溪也觉得 Rust 香!

一、OpenAI 用 Rust 重写 Codex CLI OpenAI 已用 Rust 语言重写了其 AI 命令行编程工具 Codex CLI&#xff0c;理由是此举能提升性能和安全性&#xff0c;同时避免对 Node.js 的依赖。他们认为 Node.js “可能让部分用户感到沮丧或成为使用障碍”。 Codex 是一款实验性编程代理…...

人工智能:网络安全的“智能守护者”

在数字化时代&#xff0c;网络安全已经成为企业和个人面临的重大挑战。随着网络攻击的复杂性和频率不断增加&#xff0c;传统的安全防护手段已经难以应对。人工智能&#xff08;AI&#xff09;技术的出现为网络安全带来了新的希望和解决方案。本文将探讨人工智能在网络安全中的…...

Python60日基础学习打卡Day46

一、 什么是注意力 注意力机制的由来本质是从onehot-elmo-selfattention-encoder-bert这就是一条不断提取特征的路。各有各的特点&#xff0c;也可以说由弱到强。 其中注意力机制是一种让模型学会「选择性关注重要信息」的特征提取器&#xff0c;就像人类视觉会自动忽略背景&…...

综述论文解读:Editing Large Language Models: Problems, Methods, and Opportunities

论文为大语言模型知识编辑综述&#xff0c;发表于自然语言处理顶会ACL(原文链接)。由于目前存在广泛的模型编辑技术&#xff0c;但一个统一全面的分析评估方法&#xff0c;所以本文&#xff1a; 1、对LLM的编辑方法进行了详尽、公平的实证分析&#xff0c;探讨了它们各自的优势…...

WEB3全栈开发——面试专业技能点P1Node.js / Web3.js / Ethers.js

一、Node.js 事件循环 Node.js 的事件循环&#xff08;Event Loop&#xff09;是其异步编程的核心机制&#xff0c;它使得 Node.js 可以在单线程中实现非阻塞 I/O 操作。 &#x1f501; 简要原理 Node.js 是基于 libuv 实现的&#xff0c;它使用事件循环来处理非阻塞操作。事件…...

Vscode下Go语言环境配置

前言 本文介绍了vscode下Go语言开发环境的快速配置&#xff0c;为新手小白快速上手Go语言提供帮助。 1.下载官方Vscode 这步比较基础&#xff0c;已经安装好的同学可以直接快进到第二步 官方安装包地址&#xff1a;https://code.visualstudio.com/ 双击一直点击下一步即可,记…...

Java八股文——MySQL篇

文章目录 Java八股文——MySQL篇慢查询如何定位慢查询&#xff1f;如何分析慢SQLExplain标准答案 索引索引类型索引底层数据结构什么是聚簇索引什么是非聚簇索引&#xff1f;&#xff08;二级索引&#xff09;&#xff08;回表&#xff09;聚集索引选取规则回表查询 什么是覆盖…...

Oracle数据库学习笔记 - 创建、备份和恢复

Oracle数据库学习笔记 创建&#xff0c;备份和恢复 Oracle 版本基于11g 尽量不使用图形界面方式&#xff0c;操作适用于linux和windows 创建数据库 创建实例 # 步骤1&#xff1a;设置环境变量 export ORACLE_SIDmyorcl export ORACLE_HOME/u01/app/oracle/product/19.0.0/dbh…...

Go语言--语法基础5--基本数据类型--输入输出(1)

I : input 输入操作 格式化输入 scanf O &#xff1a; output 输出操作 格式化输出 printf 标准输入 》键盘设备 》 Stdin 标准输出 》显示器终端 》 Stdout 异常输出 》显示器终端 》 Stderr 1 、输入语句 Go 语言的标准输出流在打印到屏幕时有些参数跟别的语言…...

永磁同步电机无速度算法--自适应龙贝格观测器

一、原理介绍 传统龙伯格观测器&#xff0c;在设计观测器反馈增益矩阵K时&#xff0c;为简化分析与设计&#xff0c;根据静止两相坐标系下的对称关系&#xff0c;只引入了K、K,两个常系数&#xff0c;且在实际应用时&#xff0c;大多是通过试凑找到一组合适的反馈增益系数缺乏…...

LangChain工具集成实战:构建智能问答系统完整指南

导读&#xff1a;在人工智能快速发展的今天&#xff0c;如何构建一个既能理解自然语言又能调用外部工具的智能问答系统&#xff0c;成为许多开发者面临的核心挑战。本文将为您提供一套完整的解决方案&#xff0c;从LangChain内置工具包的基础架构到复杂系统的工程实践。 文章深…...

【razor】x264 在 的intra-refresh和IDR插帧

你提到的是这样一个情况: 使用 DirectShow 采集,帧率稳定(如回调了20帧)使用 x264 的 total intra refresh 模式(intra-refresh=1) 进行编码但编码过程中「隔几十秒才有一帧intra(关键帧)」这不正常,具体分析如下: 🎯 一、问题核心 x264 的 intra refresh 模式(特…...

分库分表的取舍

文章目录 大数据量下采用**水平分表**的缺点**1. 跨表查询复杂性与性能下降****2. 数据分布不均衡****3. 分布式事务与一致性问题****4. 扩展性受限****5. 查询条件限制与索引管理复杂****6. 数据迁移与维护成本高****7. 业务逻辑复杂度增加****总结** shardingJdbc分片策略**1…...

随机算法一文深度全解

随机算法一文深度全解 一、随机算法基础1.1 定义与核心特性1.2 算法优势与局限 二、随机算法经典案例2.1 随机化快速排序原理推导问题分析与策略代码实现&#xff08;Python、Java、C&#xff09; 2.2 蒙特卡罗方法计算 π 值原理推导问题分析与策略代码实现&#xff08;Python…...

在 Conda 环境下配置 Jupyter Notebook 环境和工作目录

作为数据科学家或Python开发者&#xff0c;Jupyter Notebook 是我们日常工作的得力工具。本文将详细介绍如何在 Conda 环境中配置 Jupyter Notebook&#xff0c;包括环境设置和工作目录管理&#xff0c;帮助你打造高效的工作流程。 为什么要在 Conda 环境中使用 Jupyter Noteb…...

MS39531N 是一款正弦驱动的三相无感直流电机驱动器,具有最小振动和高效率的特点

MS39531N 是一款正弦驱动的三相无感直流电机驱动器&#xff0c;具有最小振动和高效率的特点 简述 MS39531 是一款正弦驱动的 三相无感直流电机驱动器 &#xff0c;具有最小振动和高效率的特点。该驱动器内部集成了基本的闭环速度控制功能&#xff0c;能够根据特定的应用定制电…...

web3-基于贝尔曼福特算法(Bellman-Ford )与 SMT 的 Web3 DeFi 套利策略研究

web3-基于贝尔曼福特算法&#xff08;Bellman-Ford &#xff09;与 SMT 的 Web3 DeFi 套利策略研究 如何找到Defi中的交易机会 把defi看做是一个完全开放的金融产品图表&#xff0c;可以看到所有的一切东西&#xff1b;我们要沿着这些金融图表找到一些最优的路径&#xff0c;就…...

分析 java 的 Map<String,Map<String, List<Map<String,Integer>>>>

import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;public class Test02 {public static void main(String[] args) {//分析方法&#xff1a;由外层向内层逐渐拆解要定义的变量。再由内向外进行变量赋值//外层第一层&#x…...

ChatterBox - 轻巧快速的语音克隆与文本转语音模型,支持情感控制 支持50系显卡 一键整合包下载

ChatterBox 是一个近期备受关注的开源语音克隆与文本转语音&#xff08;TTS&#xff09;模型&#xff0c;由 Resemble AI 推出&#xff0c;具备体积轻巧及超快的推理速度等特色。它也是首个支持情感夸张控制的开放源代码 TTS 模型&#xff0c;这一强大功能能让您的声音脱颖而出…...

前端开发面试题总结-HTML篇

文章目录 HTML面试高频问答一、HTML 的 src 和 href 属性有什么区别?二、什么是 HTML 语义化?三、HTML的 script 标签中 defer 和 async 有什么区别?四、HTML5 相比于 HTML有哪些更新?五、HTML行内元素有哪些? 块级元素有哪些? 空(void)元素有哪些?六、iframe有哪些优点…...

嵌入式学习--江协stm32day4

只能说拖延没有什么好结果&#xff0c;欠下的债总是要还的。 ADC 模拟信号转化为数字信号&#xff0c;例如温度传感器将外部温度的变化&#xff08;模拟信号&#xff09;&#xff0c;转换为内部电压的变化&#xff08;数字信号&#xff09; IN是八路输入&#xff0c;下方是选择…...

【Matlab】连接SQL Server 全过程

文章目录 一、下载与安装1.1 SQL Server1.2 SSMS1.3 OLE DB 驱动程序 二、数据库配置2.1 SSMS2.2 SQL Server里面设置2.3 设置防火墙2.4 设置ODBC数据源 三、matlab 链接测试 一、下载与安装 微软的&#xff0c;所以直接去微软官方下载即可。 1.1 SQL Server 下载最免费的Ex…...

MS8551/MS8552/MS8554 单电源、轨到轨输入输出、高精度运放,可替代AD8551/AD8552/AD8554

MS8551/MS8552/MS8554 单电源、轨到轨输入输出、高精度运放&#xff0c;可替代AD8551/AD8552/AD8554 简述 MS8551/8552/8554 是轨到轨输入输出的高精度运算放大器&#xff0c;它有极低的输入失调电压和偏置电流&#xff0c;单电源电压范围为 1.8V 到 5V 。 MS8551/8552/85…...

什么是 Ansible 主机和组变量

Ansible 是一款强大的自动化工具&#xff0c;可简化配置管理、应用程序部署和预配等 IT 任务。其最有价值的功能之一是能够定义变量&#xff0c;从而为不同的主机和组定制剧本。本文将解释 Ansible 中组变量和主机变量的概念&#xff0c;并通过实际示例说明它们的用法。 Ansib…...

F#语言的区块链

F#语言在区块链中的应用 引言 区块链技术在过去十年中迅速崛起&#xff0c;成为了推动金融、供应链、物联网等多个领域创新的重要力量。近年来&#xff0c;随着区块链技术的普及&#xff0c;各种编程语言也纷纷被应用于区块链的开发中。F#语言作为一种功能性编程语言&#xf…...

9.RV1126-OPENCV 视频的膨胀和腐蚀

一.膨胀 1.视频流的膨胀流程 之前膨胀都是在图片中进行的&#xff0c;现在要在视频中进行也简单&#xff0c;大概思路就是&#xff1a;获取VI数据&#xff0c;然后把VI数据给Mat化发给VENC模块&#xff0c;然后VENC模块获取&#xff0c;这样就完成了。流程图&#xff1a; 2.代…...

查找 Vue 项目中未使用的依赖

在 Vue 项目中查找未使用的依赖可以通过以下几种方法&#xff1a; 1. 使用 depcheck 工具 depcheck 是一个专门用于查找项目中未使用依赖的工具。 安装&#xff1a; bash npm install -g depcheck使用&#xff1a; bash depcheck它会列出&#xff1a; 未使用的依赖缺失…...

华为OD机考-内存冷热标记-多条件排序

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextInt();int[] arr new int[a];for(int…...