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

C++入门小馆: 深入了解STLlist

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go!

我的博客:yuanManGan

我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记  闲言碎语小记坊 题山采玉 领略算法真谛

了解使用list:

list的这些接口相信大家已经很熟练了。

只不过我们没有重载流运算符,和下标访问运算符。

模拟实现list类:

我们实现的list是双向循环链表。

我们还是来看看stl源码吧:

我们list中要构造一个类来表示节点,之前用c语言实现时也是用struct来实现节点node,这里我们可以使用class也可以使用struct,但我们选择struct来实现,使用 struct 而非 class 是出于效率、代码简洁性和设计一致性的考虑。尽管 struct 和 class 在 C++ 中功能几乎相同(仅默认访问权限不同),但选择 struct 更符合节点作为“纯数据聚合体”的定位,同时也延续了 C++ 社区中 struct 用于底层数据结构的传统。

 这里定义的next和prev指针用空指针来定义,而后面使用要进行强转

随便看一下代码,不用理解。

 我们实现时就不用这样设计了我们就直接用node*来实现。

list的成员变量也很简单就一个node对象

再看看初始化:

它把初始化分装成了一个函数。

也就是哨兵位:

这里实现的方式依旧是利用内存池,我们暂时实现就利用new吧。

最后再看看insert。

这里还是一个问题,我们实现模板时,不能将定义和声明定义在两个文件,会在编译时出现错误,但我们可以定义和声明写在同一个文件,这里的insert比较小的就直接写在这里面。

如果认真学习了c语言实现链表的同学看这个应该没有问题,闲话少叙直接开写:

大体结构:

namespace refrain
{template<class T>struct list_node{list_node* _prev;list_node* _next;T data;list_node(const T& x = T()): _prev(nullptr), _next(nullptr), data(x){}};template<class T>class list{typedef list_node<T> Node;public:private:Node _head;size_t _size;};}

这里list_node里面的构造函数,里面给的缺省值给的是匿名对象,但有的同学会说,主ber匿名对象不是只有自定义类型有吗,如果T是int类型呢?因为这种原因,设计C++的祖师爷就将匿名对象加强了,内置类型也有匿名对象。

这里多定义了一个size是为了实现size函数。

实现默认构造函数时我们也多创建一个函数empty_initialize(),方便以后复用。

这里调试看看也是没问题的。

我们为了好实现以后的功能先实现一下push_back,其实我们只要实现了insert就可以复用insert但为了方便先实现push_back吧。

我们tail就是_head的prev,所以实现该操作时间复杂度是O(n)。

void push_back(const T& x)
{// tail newnode _headNode* tail = _head->_prev;Node* newnode = new Node(x);tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;_size++;
}

 

也是没有问题。

接下来就是实现迭代器了,但我们可不可以想vector一样使用原生指针,原生指针解引用就是数值而我们node*解引用后是个结构体还得.data才能找到值,然后++等操作也难实现。这时我们就需要将迭代器封装成类了。

我们只需要操作我们需要的操作的运算符就ok了。 

template<class T>
struct list_iterator
{typedef list_node<T> Node;typedef list_iterator<T> Self;Node* _node;list_iterator(Node* node): _node(node){}T& operator*(){return _node->data;}Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp(*this);++*this;return tmp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self tmp(*this);--*this;return tmp;}bool operator==(const self& x) const {return _node == x.node; }bool operator!=(const self& x) const {return _node != x.node; }
};
typedef list_node<T> Node;
typedef list_iterator<T> Self;

重命名这些一是美观,二是等会再说,库里面更喜欢重命名。 

这时iterator类,我们再看看list类里面的iterator吧:

很简单

typedef list_iterator<T> iterator;iterator begin()
{return _head->_next;
}iterator end()
{return _head;
}

 有了迭代器就可以实现范围for就可以实现遍历逻辑。

 假如我们要实现一个打印函数:

出了个什么问题呢?我们没有实现const迭代器就不能使用const。那我们实现一下吧,我们的const的迭代器和普通迭代器有什么区别呢?对const迭代器指向的内容不能修改

typedef const iterator const_iterator;

 这样能不能实现const迭代器呢,const iterator表示迭代器本身不能修改,而指向的内容可以修改。我们只需要改一下重载运算符解引用这个地方就行了。

const T& operator*()
{return _node->data;
}

 只需要改变这一点就能实现const迭代器了,那我们重新定义一个类?这样代码就太冗余了,我们可以将改重载的返回值弄成模板就行了,让编译器帮我们写。

	template<class T, class Ref>struct list_iterator{typedef list_node<T> Node;typedef list_iterator<T, Ref> Self;Node* _node;list_iterator(Node* node): _node(node){}Ref operator*(){return _node->data;}
.........................................

 类里面:

const_iterator begin() const
{return _head->_next;
}const_iterator end() const
{return _head;
}

实现出来的print函数就可以正常使用了。

实现完迭代器我们就可以安心的实现插入删除了

insert 

void insert(iterator pos, const T& x)
{//prev newnode curNode* cur = pos->_node;Node* newnode = new Node(x);Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;_size++;
}

我们就可以采用复用insert来实现头插尾插操作了。 

		void push_back(const T& x){// tail newnode _head/*Node* tail = _head->_prev;Node* newnode = new Node(x);tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;_size++;*/insert(end(), x);}void push_front(const T& x){insert(begin(), x);}

注意实现erase操作时会导致迭代器失效所以要返回下一个位置的迭代器。

注意不能删除哨兵位。

iterator erase(iterator pos)
{assert(pos != end());//prev del nextNode* del = pos->_node;Node* prev = del->_prev;Node* next = del->_next;prev->_next = next;next->_prev = prev;delete del;--_size;return next;//return iterator(next);
}

 一样的复用逻辑:

	void pop_front(){erase(begin());}void pop_back(){erase(--end());}

size函数就不用说了:

size_t size()
{return _size;
}

再来写写差点漏掉的析构吧!

先实现一个clear函数

void clear()
{auto it = begin();while (it != end()){it = erase(it);}
}

析构函数:

~list()
{clear();delete _head;_head = nullptr;
}

接下来就是赋值运算符重载,和拷贝构造这些了:

拷贝构造就直接复用咯.

list(list<T>& lt)
{empty_init();while (auto & e : lt){push_back(e);}
}

swap也很简单

void swap(list<T>& lt)
{std::swap(_head, lt->_head);std::swap(_size, lt._size);
}

赋值运算符重载:

list<T>& operator=(list<T> lt)
{swap(lt);return *this;
}

 再来写写大括号构造

list(initializer_list<T> il)
{empty_init();for (auto& e : il){push_back(e);}
}

就实现完了,完结撒花! 

相关文章:

C++入门小馆: 深入了解STLlist

嘿&#xff0c;各位技术潮人&#xff01;好久不见甚是想念。生活就像一场奇妙冒险&#xff0c;而编程就是那把超酷的万能钥匙。此刻&#xff0c;阳光洒在键盘上&#xff0c;灵感在指尖跳跃&#xff0c;让我们抛开一切束缚&#xff0c;给平淡日子加点料&#xff0c;注入满满的pa…...

【Git】Fork和并请求

当你在 GitHub 或其他代码托管平台上 Fork 了一个项目后&#xff0c;你可以基于你的 Fork 进行开发&#xff0c;并通过 Pull Request&#xff08;PR&#xff09; 的方式将你的更改提交给原始项目&#xff08;也称为上游仓库&#xff09;。以下是完整的流程和步骤&#xff1a; 1…...

小白学习java第15天:JDBC

1.数据库驱动 想一下我们之前是怎么操作数据库&#xff0c;是不是使用SQL语句对其mysql数据库管理系统&#xff0c;然后管理系统在进行数据库&#xff08;硬盘文件里面的&#xff09;进行操作。那么我现在想使用应用程序对其数据库进行操作&#xff0c;应该怎么办呢&#xff1…...

大模型应用开发(PAFR)

Prompt问答 特征:利用大模型推理能力完成应用的核心功能 应用场景&#xff1a; 文本摘要分析 舆情分析 坐席检查 AI对话 AgentFunction Calling 特征&#xff1a;将应用端业务能力与AI大模型推理能力结合&#xff0c;简化复杂业务功能开发 应用场景: 旅行指南 数据…...

Go 剥离 HTML 标签的三把「瑞士军刀」——从正则到 Bluemonday

1 为什么要「剥皮」&#xff1f; 安全&#xff1a;去掉潜在的 <script onload…> 等恶意标签&#xff0c;防止存储型 XSS。可读性&#xff1a;日志、消息队列、搜索索引里往往只需要纯文本。一致性&#xff1a;不同富文本编辑器生成的 HTML 五花八门&#xff0c;统一成「…...

U-Mail邮件加速服务:全球链路加速,安全稳定收发

由于跨国网络拥堵、带宽不稳定等因素&#xff0c;导致海外用户在使用企业邮箱收发邮件时&#xff0c;经常出现邮件收发不畅的问题。针对这种情况&#xff0c;U-Mail正式推出了邮件加速服务&#xff0c;U-Mail邮件加速服务依托全球优质加速链路和转发集群服务器&#xff0c;为海…...

实战交易策略 篇十七:翻倍黑马交易策略

文章目录 系列文章设置指标判断大盘买入的条件判断大盘卖出的条件精选个股,挖掘明天能上涨的黑马熊市选股牛市选股短线最佳买点短线最佳卖点“翻倍”的核心秘籍系列文章 实战交易策略 篇一:奥利弗瓦莱士短线交易策略 实战交易策略 篇二:杰西利弗莫尔股票大作手操盘术策略 实…...

反爬策略应对指南:淘宝 API 商品数据采集的 IP 代理与请求伪装技术

一、引言​ 在电商数据驱动决策的时代&#xff0c;淘宝平台海量的商品数据极具价值。然而&#xff0c;淘宝为保障平台安全和用户体验&#xff0c;构建了严密的反爬体系。当采集淘宝 API 商品数据时&#xff0c;若不采取有效措施&#xff0c;频繁的请求极易触发反爬机制&#x…...

论文精读:大规模MIMO波束选择问题的量子计算解决方案

论文精读&#xff1a;大规模MIMO波束选择问题的量子计算解决方案 概要&#xff1a; 随着大规模多输入多输出系统&#xff08;MIMO&#xff09;在5G及未来通信技术中的应用&#xff0c;波束选择问题&#xff08;MBS&#xff09;成为提升系统性能的关键。传统的波束选择方法面临计…...

精益数据分析(13/126):洞察数据关系,灵活调整创业方向

精益数据分析&#xff08;13/126&#xff09;&#xff1a;洞察数据关系&#xff0c;灵活调整创业方向 大家好&#xff01;在创业和数据分析的探索之路上&#xff0c;每一次的学习都是成长的宝贵机会。今天&#xff0c;咱们接着深入学习《精益数据分析》&#xff0c;一起探索相…...

uniapp-商城-37-shop 购物车 选好了 进行订单确认3 支付栏

支付栏 就是前面用的 car-Layout 在shop也用来这个组件 只是在那里用来的是购物车。 1、 样式 我们开始进入这个页面是点击的shop的购物篮 到这里就变成了支付栏 其实他们是同一个组件 只是做了样式区分 2、具体看看样式和代码 2.1 消失了购物车和改变了按钮名字 如何…...

【LLM+Code】Claude Code Agent 0.2.9 版本PromptTools最细致解读

一、Claude Code 是anthropic团队开发的一个code agent bash工具 具体使用文档&#xff1a;https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview 1.1 安装/使用Claude Code 自行安装 npm install -g anthropic-ai/claude-code cd your-project-dire…...

ISCTF2024-misc(部分)

前言 之前写的&#xff0c;一直没发&#xff0c;留个记录吧&#xff0c;万一哪天记录掉了起码在csdn有个念想 1.少女的秘密花园 打开是个图片 随波逐流binwalk一下分离得到一个zip&#xff0c;解压得到base_misc发现是zip 爆破得到密码 解压得到一个txt&#xff0c;将里面的…...

U8G2在PC端模拟(C语言版本)

前提&#xff1a; 电脑已经准备好mingw编译器环境&#xff0c;已经加入环境变量. 测试方法&#xff1a; window下打开cmd,输入gcc -v 会有信息打印. u8g2 u8g2官方支持sdl2接口&#xff0c;已经做好了适配. 所以只需要在使用的开发环境配置好SDL2路径即可. sdl2和u8g2的适配…...

【计算机视觉】CV实战项目 - 深入解析基于HOG+SVM的行人检测系统:Pedestrian Detection

深入解析基于HOGSVM的行人检测系统&#xff1a;从理论到实践 技术核心&#xff1a;HOGSVM检测框架HOG特征原理SVM分类器 项目架构与数据准备INRIA Person数据集目录结构 实战指南&#xff1a;从零构建检测系统环境配置完整训练流程检测应用 关键技术问题与解决方案1. 难例挖掘不…...

如何借助全球动态IP实现多平台账号的批量注册?

无论是社交网络、在线购物平台还是专业应用软件&#xff0c;账号的创建和使用都是必不可少的。然而&#xff0c;在面对不同平台各自的注册限制和策略时&#xff0c;如何高效、安全且合法地进行账号批量注册成为了亟待解决的问题。本文将探讨全球动态IP在这一过程中的作用及其如…...

PR第二课--混剪

1.音乐打点 1.1 手动打点 按钮(如图),或者,快捷键M(如果在已有打点处,再次按M键会进入对标记点的设置界面,如下下图) 1.2 插件打点 一段音乐中,有明显的鼓点时,可以使用打点插件,快捷打点;如果鼓点不明显的话,最好还是手动打点,用插件打点会打出大量的标记点,…...

网页不同渲染方式的应对与反爬机制的处理——python爬虫

文章目录 写在前面爬虫习惯web 网页渲染方式服务器渲染客户端渲染 反爬机制使用session对象使用cookie让请求头信息更丰富使用代理和随机延迟 写在前面 本文是对前两篇文章所介绍的内容的补充&#xff0c;在了解前两篇文章——《爬虫入门与requests库的使用》和《BeautifulSou…...

高级电影感户外街拍人像摄影后期Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色介绍 高级电影感户外街拍人像摄影后期 Lr 调色&#xff0c;是运用 Adobe Lightroom 软件&#xff0c;对户外街拍的人像照片进行后期处理&#xff0c;以塑造出具有电影质感的独特视觉效果。此调色过程借助 Lr 丰富的工具与功能&#xff0c;从色彩、光影、对比度等多维度着手…...

JAVA设计模式——(三)桥接模式

JAVA设计模式——&#xff08;三&#xff09;桥接模式&#xff08;Bridge Pattern&#xff09; 介绍理解实现武器抽象类武器实现类涂装颜色的行为接口具体颜色的行为实现让行为影响武器修改武器抽象类修改实现类 测试 适用性 介绍 将抽象和实现解耦&#xff0c;使两者可以独立…...

类加载器与jvm的内存

1. 类加载器与内存的关系 类加载器的字节码放在方法区&#xff08;元空间&#xff09;中&#xff0c;同时类加载器加载类后类的信息&#xff08;成员变量、成员方法及修饰符等&#xff09;存放在方法区中。类的信息所占内存的回收要同时满足两个条件&#xff1a;类的实例被回收…...

docker 配置代理

说明&#xff1a;该方法仅对 docker 程序本身拉取镜像的时候有效&#xff0c;对命令行无效。 docker 配置代理有 2 中方法 1.Daemon configuration 直接在 /etc/docker/daemon.json 文件中配置 {"proxies": {"http-proxy": "http://proxy.example.…...

【硬核干货】JetBrains AI Assistant 干货笔记

快进来抄作业&#xff0c;小编呕心沥血整理的 JetBrains AI Assistant 超干货笔记&#xff01; 原文链接&#xff1a;【硬核干货】JetBrains AI Assistant 干货笔记 关于晓数神州 晓数神州坚持以“客户为中心”的宗旨&#xff0c;为客户提供专业的解决方案和技术服务&#xff…...

Linux部署ragflow,从安装docker开始~

安装docker https://download.docker.com/linux/static/stable/x86_64/docker-28.0.1.tgz #首先创建一个文件夹&#xff0c;存放我们需要的各类文件,并切换到该目录 mkdir /project && cd /project #此时我们的工作目录已经切换到刚刚创建的文件夹下了&#xff0c;接…...

施磊老师基于muduo网络库的集群聊天服务器(七)

文章目录 数据表字符集问题支持中文和英文**为什么使用 utf8mb4&#xff1f;** 推荐 查看整个表, 再单独修改 客户端群组功能创建群组添加群组群组聊天接收在线群组消息接收离线群组消息补充服务器事件处理器补充服务器查询群组列表问题解决测试 目前报错总结目前为止最恶心的错…...

多态以及多态底层的实现原理

本章目标 1.多态的概念 2.多态的定义实现 3.虚函数 4.多态的原理 1.多态的概念 多态作为面对三大特性之一,它所指代的和它的名字一样,多种形态.但是这个多种形态更多的指代是函数的多种形态. 多态分为静态多态和动态多态. 静态多态在前面已经学习过了,就是函数重载以及模板,…...

使用Go语言实现轻量级消息队列

文章目录 一、引言1.1 消息队列的重要性1.2 为什么选择Go语言1.3 本文实现的轻量级消息队列特点 二、核心设计2.1 消息队列的基本概念2.1.1 消息类型定义2.1.2 消息结构设计 2.2 架构设计2.2.1 基于Go channel的实现方案2.2.2 单例模式的应用2.2.3 并发安全设计 2.3 消息发布与…...

Vue3后代组件多祖先通讯设计方案

在 Vue3 中&#xff0c;当需要设计一个被多个祖先组件使用的后代组件的通讯方式时&#xff0c;可以采用以下方案&#xff08;根据场景优先级排序&#xff09;&#xff1a; 方案一&#xff1a;依赖注入&#xff08;Provide/Inject&#xff09; 响应式上下文 推荐场景&#xff…...

路由与OSPF学习

【路由是跨网段通讯的必要条件】 路由指的是在网络中&#xff0c;数据包从源主机传输到目的主机的路径选择过程。 路由通常涉及以下几个关键元素&#xff1a; 1.路由器&#xff1a;是一种网络设备&#xff0c;负责将数据包从一个网络传输到另一个网络。路由器根据路由表来决定…...

CUDA编程之Grid、Block、Thread线程模型

一、线程模型:Grid、Block、Thread概念 ‌1. 层级定义‌ ‌Thread(线程)‌ CUDA中最基本的执行单元,对应GPU的单个CUDA核心(SP)。每个线程独立执行核函数指令,拥有独立的寄存器和局部内存空间‌。 ‌Block(线程块)‌ 由多个线程组成(通常为32的倍数),是逻辑上的并…...