【1++的C++初阶】之适配器

👍作者主页:进击的1++
🤩 专栏链接:【1++的C++初阶】

文章目录

  • 一,什么是适配器
  • 二,栈与队列模拟实现
  • 三,优先级队列
  • 四,reverse_iterator

一,什么是适配器

在这里插入图片描述
适配器作为STL的六大组件之一,其本质是一种设计模式,将一个class的接口转换为另一个class的接口。比如说我们接下来要进行模拟实现的stack。若是以vector为底层,其实就是对vector接口的再次封装。因此其虽然也能够存储数据,但在STL中其却不属于容器。

二,栈与队列模拟实现

栈与队列的详细剖析与说明在前面的【1++的数据结构初阶】中已经写过有关文章。若有疑惑可移步至专栏中查看。本篇中进行的实现主要基于适配器的设计模式,因此底层较为简单。
栈的实现

template <class T,class container=std::deque<T>>class stack{public:void push(const T& val){_con.push_back(val);}T& top(){return _con.back();}void pop(){_con.pop_back();}size_t size(){return _con.size();}bool empty(){return _con.emnpty();}private:container _con;};

队列的实现

template<class T,class container=std::deque<T>>class queue{public:void push(const T& val){_con.push_back(val);}void pop(){_con.pop_front();}T& front(){return _con.front();}T& back(){return _con.back();}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:container _con;};

可能有人会疑惑,模板中的container是什么鬼?
在这里插入图片描述
来,让我们看看官方的解释:
在这里插入图片描述
其就是存储元素的内部容器的类型
在直接点就是成员类型。例如:stack中的成员——_con的类型就为deque。
那么问题来了什么又是deque呢?
在这里插入图片描述
接下来我们对deque进行一个简单的介绍了。
deque是一种双端队列,其可以在头尾进行插入和删除,并且时间复杂度为O(1)。与vector相比,其可以进行头插与头删;与list相比,其对数据的随机访问的效率高。
是不是对deque的底层实现越发的好奇了。

在这里插入图片描述
让我们来解开这层神秘的面纱。
deque的底层空间并不是连续的,而是一个个小块。类似于二维数组一样。
在这里插入图片描述
之所以选择deque作为栈和队列的底层默认容器,正是看中了其头尾在进行操作时的高效率。
deque若如此完美,那为什么不大量应用呢?原因在于其也有缺点。
deque在进行遍历时,要经过稍复杂的计算才能够计算出其在哪一块的哪个位置,所以,当数据量大时,其遍历的效率比较低。并且其中间的插入,删除效率也不高。

三,优先级队列

什么是priority_queue(优先级队列)?
它也是一种适配器,其在默认情况下,第一个位置的元素总是最大的。类似于堆。其底层容器的前提是可以通过随机访问迭代器进行随机访问。
priority_queue的实现

template<class T>class less{public:bool operator()(const T& left, const T& right)const{return left < right;}};template<class T>class greater{public:bool operator()(const T& left, const T& right)const{return left > right;}};template<class T,class container=std::vector<T>,class compare=greater<T>>class priority_queue{public:void adjust_up(){size_t child = _con.size() - 1;size_t parent = (child-1)/2;while (child > 0){compare com;if (com(_con[parent],_con[child])){swap(_con[child], _con[parent]);child = parent;parent=(child - 1) / 2;}else{break;}}}void adjust_down(){//默认左孩子为大----大堆前提下size_t parent = 0;size_t child = parent* 2+1;while (child < _con.size()){compare com;if ((child + 1) < _con.size() && com(_con[child], _con[child+1])){child++;}if (com(_con[parent], _con[child])){std::swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void push(const T& val){//向上调整_con.push_back(val);adjust_up();}const T& top()const{return _con[0];}void pop(){std::swap(_con.back(), _con[0]);_con.pop_back();//向下调整adjust_down();}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:container _con;};

优先级队列在push建堆时,使用的是向上调整,时间复杂度为O(logN) ,在默认为大堆的情况下,孩子结点于父亲结点比较,若大于父亲结点,则进行交换,直到小于父亲结点或者到达根节点。
在代码中,我们还发现了其比较大小的写法与以往不同。
在这里插入图片描述
这叫做做仿函数,其与普通函数的调用相差不大,但其本质是类对象调用重载后的(),即operator() 。

四,reverse_iterator

反向适配器其底层为正向迭代器。其也是适配器的一种。
具体实现如下:

template<class Iterator,class Ref,class Ptr>class reverse_iterator{public:typedef reverse_iterator<Iterator,Ref,Ptr> Riterator;reverse_iterator(Iterator it):cur(it){}Riterator operator++(){--cur;return *this;}Riterator operator--(){++cur;return *this;}Ref operator*(){Iterator tmp = cur;--tmp;return *tmp;}Ptr operator->(){return &(*operator());}bool operator!=(const Riterator& it){return cur != it.cur;}private:Iterator cur;};reverse_iterator rend(){return reverse_iterator(begin());}reverse_iterator rbegin(){return reverse_iterator(end());}

反向迭代器与rbegin(),rend() 进行搭配,通过观察我们发现,其rend(),实际返回的是begin(),rbegin()返回的是end()。恰好对称。并且,反向迭代器中的++,实际上为正向迭代器的- -; --则实际上为++。
需要注意的是operator*()的实现。其返回的是当前迭代器指向的元素的下一个元素(右往左数)。这样做的原因是:end()指向的是最后一个元素的下一位置。并且,由于对称的原因,rbegin指向的位置与end相同,因此在返回其元素的时候,就需要返回其下以位置的元素。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/8138.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【爬虫逆向案例】某道翻译js逆向—— sign解密

声明&#xff1a;本文只作学习研究&#xff0c;禁止用于非法用途&#xff0c;否则后果自负&#xff0c;如有侵权&#xff0c;请告知删除&#xff0c;谢谢&#xff01; 【爬虫逆向案例】某道翻译js逆向—— sign解密 1、前言2、步骤3、源码4、号外 1、前言 相信各位小伙伴在写…

SAMStable-Diffusion集成进化!分割、生成一切!AI绘画新玩法

自SAM「分割一切」模型推出之后&#xff0c;二创潮就开始了&#xff0c;有想法有行动&#xff01;飞桨AI Studio开发者会唱歌的炼丹师就创作出SAM进化版&#xff0c;将SAM、Stable Diffusion集成&#xff0c;实现「分割」、「生成」能力二合一&#xff0c;并部署为应用&#xf…

JVM - 运行时数据区域

文章目录 程序计数器栈堆方法区知识延申 -- 字符串常量池 程序计数器 并发情况下&#xff0c;会发生线程之间的上下文切换&#xff0c;当 线程1 的CPU时间片用完后&#xff0c;需要程序计数器记录 线程1 的下一条JVM指令的地址&#xff0c;等下一次 线程1 继续运行的时&#x…

水环境综合治理监测系统:筑牢城市水生态安全屏障

水是生命之源&#xff0c;是人类赖以生存的基础。然而&#xff0c;随着工业化、城市化的快速发展&#xff0c;水污染问题日益凸显&#xff0c;给居民的环境卫生以及用水安全带来了巨大的威胁。因此&#xff0c;加强水环境综合治理&#xff0c;保护水资源和维护生态平衡&#xf…

28.1 kibana

Kibana 是一个免费且开放的用户界面&#xff0c;能够对 Elasticsearch 数据进行可视化操作&#xff0c;从跟踪查询负载&#xff0c;到理解请求如何流经整个应用&#xff0c;都能轻松完成。 1.Kibana安装 注意要与ES版本保持一致 https://www.elastic.co/downloads/past-relea…

看完这篇,别再说不会Spring 分库分表了

多数据源&#xff0c;读写分离&#xff0c;分库分表&#xff0c;基本上已经是现在任何一个项目的基本配置了&#xff0c;在之前的文章Spring多数据源实现https://blog.csdn.net/wangerrong/article/details/131910740 里讲了多数据源的实现&#xff0c;其实已经包含了读写分离…

Linux使用教程

一、Linux命令基础 1、ls、ll命令——展示数据 ①ls命令——平铺展示数据 其中ls命令以平铺的方式展现数据 ②ll命令——列表展示数据 ll命令以列表的方式展现数据 -a选项&#xff0c;表示&#xff1a;all的意思&#xff0c;即列出全部文件&#xff08;包含隐藏的文件/文件夹…

ARM寄存器组织

一、寄存器二、ARM寄存器三、专用寄存器四、CPSR寄存器 一、寄存器 概念 寄存器是处理器内部的存储器&#xff0c;没有地址 作用 一般用于暂时存放参与运算的数据和运算结果 分类 包括通用寄存器、专用寄存器、控制寄存器 二、ARM寄存器 注 在某个特定模式下只能使用当前模…

Web浪漫历程:揭秘二十年间与您“约会”的浏览器发展

&#x1f9d1;‍&#x1f4bc; 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; &#x1f5a5;️ Node专栏&#xff1a;Node.js从入门到精通 &#x1f5a5;️ TS知识总结&#xff1a;十万字TS知识点总结 &#x1f449; 你的一键三连是我更新的最大动力❤️&#xff01;…

Kafka基础架构与核心概念

Kafka简介 Kafka是由Apache软件基金会开发的一个开源流处理平台&#xff0c;由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。架构特点是分区、多副本、多生产者、多订阅者&#xff0c;性能特点主要是…

手机照片误删除?无需担忧,点击这里,即可轻松恢复

手机照片误删除&#xff1f;无需担忧&#xff0c;点击这里&#xff0c;即可轻松恢复 开头&#xff1a;在数字化时代&#xff0c;手机已成为我们生活中不可或缺的伙伴。随着手机摄影的普及&#xff0c;我们记录了许多珍贵的瞬间和回忆。然而&#xff0c;有时候我们不小心误删除…

Python编译过程和执行原理

hello&#xff0c;这里是Token_w的文章&#xff0c;主要讲解python的基础学习&#xff0c;希望对大家有所帮助 整理不易&#xff0c;感觉还不错的可以点赞收藏评论支持&#xff0c;感谢&#xff01; 目录 一. Python执行原理二. Python内部执行过程2.1 编译过程概述2.2 过程图解…

遥感数字图像处理实验教程(韦玉春)--部分实验问题回答

个人的学习思考&#xff0c;仅供参考。 目录 实验三、图像合成和显示增强 一、目的 二、要求 三、实验 实验五、图像变换 一、目的 二、要求 三、实验 实验六、图像滤波 一、目的 二、要求 三、实验 实验七、图像分割 一、目的 二、要求 三、实验 实验八、图…

linux判断端口是否占用(好用)

netstat 一般的话使用 netstat -tunlp | grep xxx参数作用-t指明显示TCP端口-u指明显示UDP端口-l仅显示监听套接字(所谓套接字就是使应用程序能够读写与收发通讯协议(protocol)与资料的程序)-p显示进程标识符和程序名称&#xff0c;每一个套接字/端口都属于一个程序。-n不进行…

爬虫002_python程序的终端运行_文件运行_ipython的使用---python工作笔记020

用python运行一个文件,就是要写一个.py结尾的文件 然后保存 然后直接cmd中,python 然后写上py文件的路径就可以了 然后看一下内容 看一下终端中运行,直接输入python进入python环境,然后写python代码 回车运行 退出可以用exit()

设计模式——单例模式

1 概述 单例模式就是保证一个类只有一个对象实例。 为了保证无法创建多余的对象实例&#xff0c;单例类中需要自己创建对象实例&#xff0c;并把自己的构造方法私有化以防止其他地方调用创建对象&#xff0c;且需要提供一个公共的方法给其他类来获取该单例类的实例。 同时单例…

Linux笔记——rpm与yum下载软件命令介绍

系列文章目录 Linux笔记——进程管理Linux笔记——进程管理与网络监控技术讲解Linux笔记——进程管理 Linux笔记——管道相关命令以及shell编程 Linux笔记——磁盘进行分区与挂载介绍 文章目录 系列文章目录 前言 一 RPM介绍 1.1 RPM简单介绍 1.2 RPM命令语法 1.2.1 …

数学建模学习(2):数学建模各类常用的算法全解析

一、评价类算法 常见的评价算法 1.层次分析法 基本思想 是定性与定量相结合的多准则决策、评价方法。将决策的有关元素分解成 目标层、准则层和方案层 &#xff0c;并通过人们的 判断对决策方案的 优劣进行排序 &#xff0c;在此基础上进行定性和定量分析。它把人的思维过程…

Python怎么实现模式匹配

什么是模式匹配 模式匹配是一种用于在数据中寻找特定模式或结构的技术。它可以用于识别、查找和提取符合特定模式要求的数据。 在计算机科学中&#xff0c;模式匹配通常用于字符串处理和数据分析领域。一些常见的模式匹配模式包括&#xff1a; 1. 字符串匹配&#xff1a;在一…

23 自定义控件

案例&#xff1a;组合Spin Box和Horizontal Slider实现联动 新建Qt设计师界面&#xff1a; 选择Widget&#xff1a; 选择类名&#xff08;生成.h、.cpp、.ui文件&#xff09; 在smallWidget.ui中使用Spin Box和Horizontal Slider控件 可以自定义数字区间&#xff1a; 在主窗口w…