探索C嘎嘎的奇妙世界:第十九关---STL(list的模拟实现)
1. 基本框架
首先,我们先从节点的准备工作入手,请看示例:
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
//节点
template<class T>
struct ListNode
{ListNode<T>* _next;ListNode<T>* _prev;T _data;ListNode(const T& data = T()):_next(nullptr), _prev(nullptr), _data(data){}
};
在上述代码中:先定义一个双向链表的节点结构ListNode。节点结构ListNode包含以下成员变量:
1. _next:指向下一个节点的指针。
2. _prev:指向上一个节点的指针。
3. _data:存储节点数据的变量。
节点结构ListNode还包含一个构造函数,用于初始化成员变量。构造函数接受一个参数data,用于初始化_data成员变量。如果没有提供参数,则_data成员变量的默认值为T(),即T类型的默认构造函数的返回值。
该头文件还使用了iostream和assert.h两个标准头文件,并使用了std命名空间。
2. 封装迭代器
请看示例代码:
//迭代器template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;Node* _node;ListIterator(Node* node):_node(node){}// ++it;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;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}};
在上述代码中:定义了一个迭代器结构ListIterator,用于遍历双向链表。迭代器结构ListIterator包含以下成员变量和成员函数:
成员变量: _node:指向当前迭代器所指向的节点的指针。
成员函数如下:
1. 构造函数:接受一个参数node,用于初始化迭代器的节点指针。
2. 前置递增运算符(++it):将迭代器指向下一个节点,并返回自身的引用。
3. 前置递减运算符(--it):将迭代器指向上一个节点,并返回自身的引用。
4. 后置递增运算符(it++):将迭代器指向下一个节点,并返回之前的迭代器的副本。
5. 后置递减运算符(it--):将迭代器指向上一个节点,并返回之前的迭代器的副本。
6. 解引用运算符(*):返回迭代器指向节点的数据的引用。
7. 成员访问运算符(->):返回迭代器指向节点数据的指针。
8. 不等于运算符(!=):判断当前迭代器是否与另一个迭代器不相等。
9. 等于运算符(==):判断当前迭代器是否与另一个迭代器相等。
迭代器结构ListIterator还使用了两个类型别名:
1. Node:表示节点类型ListNode<T>。
2. Self:表示迭代器自身类型ListIterator<T, Ref, Ptr>。
3. 迭代器和构造函数
请看示例代码:
template<class T>class list{typedef ListNode<T> Node;public:// 不符合迭代器的行为,无法遍历//typedef Node* iterator;//typedef ListIterator<T> iterator;//typedef ListConstIterator<T> const_iterator;typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;iterator begin(){//iterator it(_head->_next);//return it;return iterator(_head->_next);}const_iterator begin() const{return const_iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator end() const{return const_iterator(_head);}list(){_head = new Node();_head->_next = _head;_head->_prev = _head;}
该部分定义了一个双向链表类list。
list类包含以下成员变量和成员函数:
1. typedef Node:类型别名,表示节点类型ListNode<T>。
2. typedef iterator:类型别名,表示迭代器类型ListIterator<T, T&, T*>。
3. typedef const_iterator:类型别名,表示常量迭代器类型ListIterator<T, const T&, const T*>。
成员函数如下:
1. begin():返回头节点的下一个节点的迭代器,用于遍历链表。
2. begin() const:返回头节点的下一个节点的常量迭代器,用于遍历常量链表。
3. end():返回头节点的迭代器,用于判断迭代结束。
4. end() const:返回头节点的常量迭代器,用于判断常量迭代结束。
5. 构造函数:初始化头节点,将头节点的_next和_prev指向自身。
注意:由于ListIterator的设计不符合迭代器的行为,无法进行迭代,所以在list类中注释掉了typedef iterator和typedef const_iterator的定义。
3. push_back、pop_back、push_front和pop_front
请看示例代码:
void push_back(const T& x)
{/*Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;*/insert(end(), x);
}void pop_back()
{erase(--end());
}void push_front(const T& x)
{insert(begin(), x);
}void pop_front()
{erase(begin());
}
这部分代码实现了list类的push_back、pop_back、push_front和pop_front成员函数。
1. push_back:在链表末尾添加一个节点。首先创建一个新的节点newnode,然后获取链表末尾的节点tail,将tail的_next指向newnode,newnode的_prev指向tail,newnode的_next指向头节点_head,头节点的_prev指向newnode。最后调用insert函数,在末尾迭代器的位置插入新节点。
2. pop_back:删除链表末尾的节点。首先获取链表末尾节点的前一个节点,然后调用erase函数,将末尾迭代器的前一个位置的节点删除。
3. push_front:在链表开头添加一个节点。调用insert函数,在开头迭代器的位置插入新节点。
4. pop_front:删除链表开头的节点。调用erase函数,将开头迭代器的位置的节点删除。
4. insert和erase
请看示例代码:
// 没有iterator失效iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* newnode = new Node(x);Node* prev = cur->_prev;// prev newnode curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}// erase 后 pos失效了,pos指向节点被释放了iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;return iterator(next);}
这部分代码实现了list类的insert和erase成员函数。
1. insert:在指定位置前插入一个节点。首先获取迭代器pos所指向的节点cur,创建一个新的节点newnode,然后获取pos的前一个节点prev。将prev的_next指向newnode,newnode的_prev指向prev,newnode的_next指向cur,cur的_prev指向newnode。最后返回一个指向新节点的迭代器。
2. erase:删除指定位置的节点。首先断言pos不等于end(),即pos不是指向末尾的迭代器。然后获取迭代器pos所指向的节点cur,分别获取cur的前一个节点prev和后一个节点next。将prev的_next指向next,next的_prev指向prev。删除cur节点,并释放内存。最后返回一个指向删除节点后的节点的迭代器。
需要注意的是,在使用erase函数删除节点时,要确保操作前的迭代器pos不会失效,否则会导致未定义行为。
到此我们只是简单的模拟实现了一下STL中list的相关接口~,后续我们会一一展开学习的,希望这篇博客能给您带来一些启发和思考!那我们下次再一起探险喽,欢迎在评论区进行讨论~~~
相关文章:
探索C嘎嘎的奇妙世界:第十九关---STL(list的模拟实现)
1. 基本框架 首先,我们先从节点的准备工作入手,请看示例: #pragma once #include<iostream> #include<assert.h> using namespace std; //节点 template<class T> struct ListNode {ListNode<T>* _next;Li…...
【分布式系统三】监控平台Zabbix对接grafana(截图详细版)
目录 一.安装grafana并启动 二.浏览器访问 三.导入zabbix数据,对接grafana 四.如何导入模版 以前两篇博客为基础 【分布式系统】监控平台Zabbix介绍与部署(命令截图版)-CSDN博客 【分布式系统】监控平台Zabbix自定义模版配置-CSDN博客 …...
SAPUI5基础知识11 - 组件配置(Component)
1. 背景 组件(Component)是SAPUI5应用程序中独立且可重用的部件。 SAPUI5提供以下两类组件: faceless组件 (class: sap.ui.core.Component): 无界面组件即没有用户界面相关的元素,用于不需要UI元素编码的场景; UI组件 (class: …...
Spring最早的源码
地址:Spring最早的源码...
热烈祝贺!全视通多家客户上榜全球自然指数TOP100!
2024年6月18日,全球医疗机构自然指数TOP100榜单发布,中国医疗机构在其中的表现尤为引人注目。 根据《自然》杂志网站发布的数据,此次公布的排名是基于(2023年3月1日至2024年2月29日)的统计数据,全球医疗机构…...
常用接口避免频繁请求
背景 在项目开发过程中我们难免会遇到一些通用的接口,需要在多个页面调用,拿去结果。比如我们常用的字典接口,后端通过字典配置一些数据,通常这些字典数据是不常更改的。我们通过字典接口传递不同的参数过去,获取到接…...
C++入门基础
前言 本篇博客讲解一下c得入门基础 💓 个人主页:普通young man-CSDN博客 ⏩ 文章专栏:C_普通young man的博客-CSDN博客 ⏩ 本人giee:普通小青年 (pu-tong-young-man) - Gitee.com 若有问题 评论区见📝 🎉欢迎大家点赞&…...
Unicode 与 UTF-8 的区别与联系
文章目录 UnicodeUTF-8联系区别Unicode 转义序列字符编码与字符的对应规则例子 Unicode 定义:Unicode 是一个字符编码标准,旨在为世界上所有的字符分配一个唯一的编码。 编码范围:Unicode 的编码范围从 0x0000 到 0x10FFFF,能够表…...
PHP MySQL 简介
PHP MySQL 简介 PHP 和 MySQL 是现代网站开发中最流行的两种技术。PHP 是一种服务器端脚本语言,而 MySQL 是一种关系型数据库管理系统。这两种技术经常一起使用,以创建动态和交互式的网页。本文将简要介绍 PHP 和 MySQL 的基本概念、它们的工作原理以及…...
Spring容器加载Bean和JVM加载类
1、JVM加载类 类的加载是在首次需要访问类的信息或实例化类的对象时发生的过程。ClassLoader负责加载类的字节码,并在内存中创建对应的Class对象,从而使得Java程序能够操作和使用这些类。 在Java中,类的加载是按需进行的,也就是…...
《简历宝典》04 - 简历的“个人信息”模块,要写性别吗?要放照片吗?
平时帮助小伙伴们优化简历的时候,我看见他们有人会写性别,有人不会写。 目录 1 招聘团队的考虑 2 性别是无法改变的,能不写就不写 3 什么情况下,需要写性别呢? 4 简历中要加照片吗? 1 招聘团队的考虑 …...
TTS模型汇总
TTS是“Text-to-Speech”的缩写,中文意思是“文本到语音”。这是一种将文本信息转换成口语的技术,通常通过计算机程序实现。TTS技术可以应用于多种场景,包括但不限于: 辅助阅读:帮助视障人士或有阅读困难的用户通过听…...
js打印出堆栈
在JavaScript中,直接获取并打印完整的调用堆栈(stack trace)并不像在一些其他语言中那样直接。不过,有几种方法可以实现类似的功能,具体取决于你的需求和运行环境(如浏览器环境或Node.js环境)。…...
论文阅读:A Survey on Evaluation of Large Language Models
A Survey on Evaluation of Large Language Models 这篇论文是由Yupeng Chang等人撰写的关于大型语言模型(LLMs)评估的综述,题为《A Survey on Evaluation of Large Language Models》。 摘要 大型语言模型(LLMs)在…...
MyBatis的简介与使用
Mybatis JDBC操作数据库的缺点 存在大量的冗余代码。手工创建 Connection、Statement 等,效率低下。手工将结果集封装成实体对象。查询效率低,没有对数据访问进行优化。 Mybatis框架 简介 MyBatis 本是 apache 的一个开源项目 iBatis, 2010年这个项目由…...
MAX98357、MAX98357A、MAX98357B小巧、低成本、PCM D类IIS放大器,具有AB类性能中文说明规格书
前言: MAX98357A支持标准I2S数据,MAX98357B支持左对齐数字音频数据。两个版本均支持8通道TDM音频数据。 IIS数字功放MAX98357开发板/评估系统 MAX98357 WLP-9(1.347x1.437mm)封装的外观和丝印AKM MAX98357 TQFN-16-EP(3x3mm)封装的外观和丝印AKK 引脚说…...
shell(2)
shell(2) 简答题 1、编写一个shell脚本,从键盘读入一个成绩,并按优秀、良好、中等、及格、不及格输出成绩。 我的答案: #/bin/bash read -p "请输入学生成绩(0-100):" score if [ $sum -gt 100 ] ;thenecho "输…...
昇思25天学习打卡营第1天|初识MindSpore
昇思MindSpore介绍 昇思MindSpore是一个全场景深度学习框架,旨在实现易开发、高效执行、全场景统一部署三大目标。 其中,易开发表现为API友好、调试难度低;高效执行包括计算效率、数据预处理效率和分布式训练效率;全场景则指框架…...
C语言字节对齐技术在嵌入式、网络与操作系统中的应用与优化
第一部分:嵌入式系统中的字节对齐 嵌入式系统通常对性能和资源有着严格的要求。在这些系统中,字节对齐的正确使用可以显著提高数据访问速度,减少内存占用,并提高系统的整体效率。 一、嵌入式系统中的字节对齐挑战 嵌入式系统中…...
如何理解李彦宏说的”不要卷模型,要卷应用
文章目录 👿AI技术的发展与转变👿不要卷模型,要卷应用👿避免“超级应用陷阱”👿大模型技术与个性化应用的关系👿结语 在2024年7月4日于上海世博中心举办的世界人工智能大会上,百度创始人、董事长…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
全面解析各类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…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
