探索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日于上海世博中心举办的世界人工智能大会上,百度创始人、董事长…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
