从零开始手写STL库:List
从零开始手写STL库–List部分
Github链接:miniSTL
文章目录
- 从零开始手写STL库–List部分
- List是什么?
- List需要包含什么函数
- 1)基础成员函数
- 2)核心功能
- 3)其他功能
- 基础成员函数的编写
- 核心功能的编写
- 其他功能编写
- 总结
List是什么?
std::list是基于双向链表的的数据结构,与std::vector基于数组不同,list在频繁插入和删除的场景中更适合应用。
List需要包含什么函数
应当具有:
1)基础成员函数
构造函数:初始化List头节点
析构函数:释放内存,当运行结束后要摧毁这个List防止内存泄漏
不同于Vector,List这种以链表为基础的容器一般不需要去拷贝新的List,也就不用手动构建拷贝构造函数和拷贝赋值操作符
2)核心功能
push_back/push_front:在List的末尾/头部加入新元素
pop_back/pop_front:移除List末尾/头部元素
size:获取List长度
clear:清空List
get:获取List中某个元素的值
remove:删除某个节点
find:查找某个值对应的节点
empty:检查List是否为空
3)其他功能
迭代器、重载输出符等等
基础成员函数的编写
List的成员:
List本身是链表,那么每个节点应该包括本节点的数据、指向上/下一个节点的指针,而List是描述这一系列节点构成的双向链表,那么只需要记录头节点、尾节点以及List长度即可
template<typename T>
class myList
{
private:struct Node{T data;Node * next;Node * prev;Node(const T & data_, Node * next_ = nullptr, Node * prev_ = nullptr): data(data_), next(next_), prev(prev_) {} };Node * head;Node * tail;size_t current_size;
public:};
构造函数和析构函数就是
public:myList() : head(nullptr), tail(nullptr), current_size(0) {}~myList() {clear(); }
再次提示,这里的构造函数用current_size(0) 初始化才是合规的,放在中括号内会浪费掉这个初始化进程
析构函数调用一下清空函数即可
核心功能的编写
1、push_back/push_front函数:在List的末尾/头部加入新元素
链表不像动态数组需要考虑分配问题,所以直接加就行了
但是也需要判断List为空的清空,如果为空,head/tail是没法取出next指针的,此时就会报错
所以在push的时候检查一下
(在力扣算法题中避免这种复杂操作的方法是构建一个虚拟头节点,就可以统一处理)
void push_back(const T & value){Node * temp = new Node(value, nullptr, tail);if(tail) tail->next = temp;else head = temp;tail = temp;current_size ++;}void push_front(const T & value){Node * temp = new Node(value, head, nullptr);if(head) head->prev = temp;else tail = temp;head = temp;current_size ++;}
2、pop_back/pop_front函数:移除List末尾/头部元素
头尾节点的删除较为简单,注意一下空列表的情况特殊处理即可
void pop_back(){if(current_size > 0){Node * temp = tail->prev;delete tail;tail = temp;if(tail) tail->next = nullptr;else head = nullptr;current_size --;}}void pop_front(){if(current_size > 0){Node * temp = head->next;delete head;head = temp;if(head) head->prev = nullptr;else tail = nullptr;current_size --;}}
这里如果删除之后发现头/尾节点是空了,说明这个List已经空了,但是另一端还没处理,所以要让另一端也为nullptr,否则有可能发生指针越界问题。
3、size函数:获取List长度
int size(){return current_size;}
4、clear函数:清空List
不同于vector那样直接将size归零,List需要考虑节点占用的内存,所以实际上是需要循环释放的
void clear()
{ while (head) { Node * temp = head;head = head->next; delete temp; } tail = nullptr; current_size = 0;
}
5、get函数:获取List中某个元素的值
这里的实现方法不是给定一个get函数,而是重载符号“[]”,这样就能更加方便地访问了
T &operator[](size_t index){Node * curr = head;for(size_t i = 0; i < index; i ++){if(!curr) throw std::out_of_range("Index out of range!");curr = curr->next;}return curr->data;}const T & operator[](size_t index) const{Node * curr = head;for(size_t i = 0; i < index; i ++){if(!curr) throw std::out_of_range("Index out of range!");curr = curr->next;}return curr->data;}
这里返回值设置为引用是考虑到一下情况
myList testList;
testList[2] = 4;
如果返回的不是引用,那么这样的赋值就会失效,并不能真的修改掉List的节点元素
6、remove函数:删除某个节点
那么这里需要查找到该节点,再进行删除,而且需要注意它是头尾节点时的情况
void remove(const T & val){Node * temp = head;while (temp && temp->data != val){temp = temp->next;}if(!temp) return;if(temp != head && temp != tail){temp->prev->next = temp->next;temp->next->prev = temp->prev;}else if(temp == head && temp == tail){head = nullptr;tail = nullptr;}else if(temp == head){head = temp->next;head->prev = nullptr;}else{tail = temp->prev;tail->next = nullptr;}current_size --;delete temp;temp = nullptr;}
7、find函数:查找某个值对应的节点
循环遍历对比就行
Node * getNode(const T & val){Node * node = head;while (node && node->data != val){node = node->next;}return node;}T *find(const T &val){Node * node = getNode(val);if(!node) return nullptr;return & node->data;}
8、empty函数:检查List是否为空
bool empty(){return current_size == 0;}
其他功能编写
迭代器
Node * begin() { return head; }Node * end() { return nullptr; }const Node * begin() const { return head; }const Node * end() const { return nullptr; }
重载<<符号
template <typename T>
std::ostream &operator<<(std::ostream &os, myList<T> &pt)
{for (auto current = pt.begin(); current; current = current->next){os << " " << current->data;}os << std::endl;return os;
}
总结
List的编写中,难点在于考虑链表为空的情况,很多个函数都需要去考虑,并且处理头尾节点,实际上是个细致的工作,并不在于思路上有多难。
在经常增删的情况下,用List会比Vector更为合适,代价是内存用得比较多,空间换时间。
相关文章:
从零开始手写STL库:List
从零开始手写STL库–List部分 Github链接:miniSTL 文章目录 从零开始手写STL库–List部分List是什么?List需要包含什么函数1)基础成员函数2)核心功能3)其他功能 基础成员函数的编写核心功能的编写其他功能编写总结 List是什么&am…...
蒙特卡洛采样
目录 蒙特卡洛采样的计算逻辑计算步骤:1. 定义问题2. 确定采样范围3. 生成随机样本点4. 计算函数值5. 估计期望值或积分值6. 计算误差具体示例:1. 定义问题2. 确定采样范围3. 生成随机样本点4. 计算函数值5. 估计积分值6. 计算误差总结蒙特卡洛采样是一种通过随机生成样本点来…...
Apache虚拟主机VirtualHost配置项详解
在Apache中,VirtualHost容器用于定义一个虚拟主机的配置,它允许在单一的物理服务器上托管多个不同的网站,每个网站可以有自己的域名、文档根目录、错误日志等。VirtualHost内的配置项非常灵活,可以包含从基本的网站信息到高级的URL重写和安全设置。 以下是一些常见的Virtu…...
OpenAI从GPT-4V到GPT-4O,再到GPT-4OMini简介
OpenAI从GPT-4V到GPT-4O,再到GPT-4OMini简介 一、引言 在人工智能领域,OpenAI的GPT系列模型一直是自然语言处理的标杆。随着技术的不断进步,OpenAI推出了多个版本的GPT模型,包括视觉增强的GPT-4V(GPT-4 with Vision&…...
从人工巡检到智能防控:智慧油气田安全生产的新视角
一、背景需求 随着科技的飞速发展,视频监控技术已成为各行各业保障安全生产、提升管理效率的重要手段。特别是在油气田这一特殊领域,由于其工作环境复杂、安全风险高,传统的监控方式已难以满足实际需求。因此,基于视频监控AI智能…...
【黑马java基础】Lamda, 方法引用,集合{Collection(List, Set), Map},Stream流
文章目录 JDK8新特性:Lambda表达式认识Lambda表达式Lambda表达式的省略规则 JDK8新特性:方法引用静态方法的引用实例方法的引用特定类型方法的引用构造器的应用 集合➡️Collection单列集合体系Collection的常用方法Collection的遍历方法迭代器增强for循…...
Stable Diffusion 使用详解(1)---- 提示词及相关参数
目录 背景 提示词 内容提示词 人物及主体特征 场景 环境光照 画幅视角 注意事项及示例 标准化提示词 画质等级 风格与真实性 具体要求 背景处理 光线与色彩 负向提示词 小结 常用工具 另外几个相关参数 迭代步数 宽度与高度 提示词引导系数 图片数量 背景…...
数据结构和算法(刷题) - 无序数组排序后的最大相邻差
无序数组排序后的最大相邻差 问题:一个无序的整型数组,求出该数组排序后的任意两个相邻元素的最大差值?要求时间和空间复杂度尽可能低。 三种方法: 排序后计算比较 简介:用任意一种时间复杂度为 O ( n log n ) O…...
HOW - React 处理不紧急的更新和渲染
目录 useDeferredValueuseTransitionuseIdleCallback 在 React 中,有一些钩子函数可以帮助你处理不紧急的更新或渲染,从而优化性能和用户体验。 以下是一些常用的相关钩子及其应用场景: useDeferredValue 用途:用于处理高优先级…...
基于A律压缩的PCM脉冲编码调制通信系统simulink建模与仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1A律压缩的原理 4.2 PCM编码过程 4.3 量化噪声与信噪比 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a 3.部分核心程序 &#…...
【入门教程一】基于DE2-115的My First FPGA 工程
1.1. 概述 这是一个简单的练习, 可以帮助初学者开始了解如何使用Intel Quartus 软件进行 FPGA 开发。 在本章节中,您将学习如何编译 Verilog 代码,进行引脚分配,创建时序约束,然后对 FPGA 进行编程,驱动开…...
mysql中的索引和分区
目录 1.编写目的 2.索引 2.1 创建方法 2.2 最佳适用 2.3 索引相关语句 3.分区 3.1 创建方法 3.2 最佳适用 Welcome to Code Blocks blog 本篇文章主要介绍了 [Mysql中的分区和索引] ❤博主广交技术好友,喜欢文章的可以关注一下❤ 1.编写目的 在MySQL中&…...
项目实战--C#实现图书馆信息管理系统
本项目是要开发一个图书馆管理系统,通过这个系统处理常见的图书馆业务。这个系统主要功能是:(1)有客户端(借阅者使用)和管理端(图书馆管理员和系统管理员使用)。(2&#…...
信号【Linux】
文章目录 信号处理方式(信号递达)前后台进程 终端按键产生信号kill系统调用接口向进程发信号阻塞信号sigset_tsigprocmasksigpending内核态与用户态:内核空间与用户空间内核如何实现信号的捕捉 1、信号就算没有产生,进程也必须识别…...
Kafka Producer之ACKS应答机制
文章目录 1. 应答机制2. 等级03. 等级14. 等级all5. 设置等级6. ISR 1. 应答机制 异步发送的效率高,但是不安全,同步发送安全,但是效率低。 无论哪一种,有一个关键的步骤叫做回调,也就是ACKS应答机制。 其中ACKS也分…...
【深入理解SpringCloud微服务】深入理解Eureka核心原理
深入理解Eureka核心原理 Eureka整体设计Eureka服务端启动Eureka三级缓存Eureka客户端启动 Eureka整体设计 Eureka是一个经典的注册中心,通过http接收客户端的服务发现和服务注册请求,使用内存注册表保存客户端注册上来的实例信息。 Eureka服务端接收的…...
算法——滑动窗口(day7)
904.水果成篮 904. 水果成篮 - 力扣(LeetCode) 题目解析: 根据题意我们可以看出给了我们两个篮子说明我们在开始采摘到结束的过程中只能有两种水果的种类,又要求让我们返回收集水果的最大数目,这不难让我们联想到题目…...
Django学习第一天(如何创建和运行app)
前置知识: URL组成部分详解: 一个url由以下几部分组成: scheme://host:port/path/?query-stringxxx#anchor scheme:代表的是访问的协议,一般为http或者ftp等 host:主机名,域名,…...
VScode连接虚拟机运行Python文件的方法
声明:本文使用Linux发行版本为rocky_9.4 目录 1. 在rocky_9.4最小安装的系统中,默认是没有tar工具的,因此,要先下载tar工具 2. 在安装好的vscode中下载ssh远程插件工具 3. 然后连接虚拟机 4. 查看python是否已经安装 5. 下载…...
通义千问AI模型对接飞书机器人-模型配置(2-1)
一 背景 根据业务或者使用场景搭建自定义的智能ai模型机器人,可以较少我们人工回答的沟通成本,而且可以更加便捷的了解业务需求给出大家设定的业务范围的回答,目前基于阿里云的通义千问模型研究。 二 模型研究 参考阿里云帮助文档…...
FastCI:基于智能缓存的CI/CD构建加速方案
1. 项目概述:当CI/CD遇上二进制制品管理如果你是一名开发工程师,或者正在负责团队的持续集成与交付(CI/CD)流程,那么你一定对“构建慢”、“依赖下载卡顿”、“制品管理混乱”这几个词深恶痛绝。尤其是在微服务和云原生…...
从微积分到数学分析:给工科生和跨专业考研党的B站学习路线图(附视频清单)
从微积分到数学分析:工科生与跨考党的B站通关指南 第一次翻开数学分析教材时,那种扑面而来的ε-δ语言是否让你想起了被高数支配的恐惧?作为带过三届考研班的数学系学长,我太理解工科生转战数学分析时的手足无措——就像让习惯开自…...
基于AI的社群风格内容生成:从原理到实践
1. 项目概述:一个能“读懂”人群的智能内容生成器最近在GitHub上看到一个挺有意思的项目,叫talsraviv/peoples-post-generator。光看名字,你可能会觉得这又是一个普通的“帖子生成器”,市面上这类工具太多了。但当我深入研究了它的…...
互联网大厂 Java 求职面试:从基础到微服务的技术深潜
互联网大厂 Java 求职面试:从基础到微服务的技术深潜在一个阳光明媚的下午,面试官坐在桌子后面,脸上挂着严肃的表情,而燕双非则略显紧张,但他努力让自己看起来从容不迫。第一轮提问面试官:首先,…...
渗透测试干货:WiFi 无线网络攻防详解,一步一步手把手教学,小白也能学会
【渗透干货-近源渗透】破解WiFi无线网络教程(保姆级教程) 前言 破解无线的原理就是大量多次重复性的密码碰撞爆破,理论上只要你的密码足够多,就可以很轻松的爆破无线网络。 总体步骤 01 连接无线网卡 02 开启网卡监听 …...
告别手动拼接字符串:用cJSON库在C语言里优雅生成JSON配置文件(附完整代码)
嵌入式设备配置管理的革命:cJSON在C语言中的高效JSON生成实践 在物联网和嵌入式系统开发中,配置文件的管理一直是个棘手问题。传统的手动拼接字符串方式不仅容易出错,维护成本也高。本文将展示如何利用cJSON库在C语言环境中优雅地生成结构化J…...
「裸辞还是在职学大模型?算清这笔账,90%的人都选错了!」
文章对比了在职和裸辞两种状态学习大模型开发的优劣势及适用人群。在职学习有稳定的工资收入和职场环境作为退路,但时间碎片化导致学习周期长;裸辞学习能集中时间高效突破,但需承担经济和心理压力。文章为两种状态的学习者提供了具体的学习策…...
Nemotron-Flash:低延迟LLM推理的混合架构设计
1. 项目背景与核心价值在自然语言处理领域,大型语言模型(LLM)虽然表现出色,但其高昂的计算成本和响应延迟始终是落地应用的瓶颈。Nemotron-Flash正是针对这一痛点提出的创新解决方案——通过混合架构设计,在保持模型性…...
在UOS/麒麟上部署东方通TongWeb 7.0.4.2,我踩过的那些坑和避坑指南
在UOS/麒麟上部署东方通TongWeb 7.0.4.2的实战避坑手册 国产化替代浪潮下,东方通中间件作为关键基础设施,其部署过程往往充满意想不到的"惊喜"。本文将以血泪经验为基础,直击ARM架构下TongWeb 7.0.4.2在统信UOS和银河麒麟系统中的典…...
探索 Taotoken 模型广场如何辅助开发者进行初步的模型选型
探索 Taotoken 模型广场如何辅助开发者进行初步的模型选型 1. 模型广场的核心功能定位 Taotoken 模型广场作为平台的核心模块,旨在为开发者提供一站式的模型浏览与筛选能力。该模块以结构化方式呈现当前平台支持的所有大模型,开发者无需逐个查阅不同厂…...
