【C++】stack、queue模拟实现+仿函数

stack、queue模拟实现+仿函数

  • stack
    • 定义
    • stack模拟实现
  • queue
    • 定义
    • queue模拟实现
  • priority_queue
    • 定义
    • priority_queue模拟实现
  • deque
    • 定义
    • 底层分析
  • 容器适配器
    • 定义
    • 种类
  • 仿函数
  • 控制类里面数据的比较逻辑
    • 回调函数
    • 仿函数
    • 两者区别

铁汁们,今天给大家分享一篇stack、queue模拟实现+仿函数,来吧,开造⛳️

stack

定义

在这里插入图片描述

  • stack是容器适配器,专门用于进行”先进后出”操作的环境中,只能在容器的一端进行数据的插入和删除操作,元素在特定容器的尾部(即栈顶)被压入和弹出。
  • 容器适配器是将特定的类进行封装,将其作为该容器的底层容器,通过调用底层容器提供的一系列成员函数来实现该容器。
  • stack的底层容器既可以是任何标准容器类模板(list、vector、deque),也可以是其他特定的容器类,它必须支持以下操作:push_back()->入栈、pop_back()->出栈、back()->获取栈顶元素、empty()->判断栈是否为空、size()->获取栈中元素总个数。
  • stack底层容器可以是list、vector、deque,若未实例化指定特定的底层容器,则默认为deque。
  • 栈空间从高地址往低地址方向增长,堆从低地址往高地址方向增长。
template<class T, class Container = deque<T>> 
class stack {private:Container _con;
};

stack模拟实现

在这里插入图片描述在这里插入图片描述

template<class T, class Container = deque<T>> 
class stack {
public:stack()  //构造空栈{  }void push(const T& val)  //入栈{_con.push_back(val);}void pop()  //出栈{_con.pop_back();}T& top() //获取栈顶元素 可读可修改{return _con.back();}const T& top()const  //获取栈顶元素 只可读不可修改{return _con.back();}bool empty()const  //判断栈是否为空{return _con.empty();}size_t size()const //获取栈中元素的总个数{return _con.size();}private:Container _con;  //底层容器创建的对象
};

queue

定义

  • queue是容器适配器,专门用于进行”先进先出”操作的环境中,从容器的一端插入数据并从容器的另一端取出数据。
  • 容器适配器是将特定的类进行封装,将其作为该容器的底层容器,通过调用底层容器提供的一系列成员函数来实现该容器。
  • queue的底层容器既可以是某些标准容器类模板(list、deque),也可以是其他特定的容器类,它必须支持以下操作:push_back()->入队、pop_front()->出队、back()->获取队尾元素、front()->获取队头元素、empty()->判断队列是否为空、size()->获取队列中元素总个数。
  • queue底层容器可以是list、deque,但不可以是vector(没有支持pop_front()),若未实例化指定特定的底层容器,则默认为deque。
  • 队列从队尾入队列,从队头从队列。
template<class T, class Container = deque<T>>
class queue {private:Container _con; //底层容器创建的对象
};

queue模拟实现

在这里插入图片描述在这里插入图片描述

template<class T, class Container = deque<T>>
class queue {
public:queue() //构造空队列{ }void push(const T& val)  //入队{_con.push_back(val);}void pop() //出队{_con.pop_front();}T& front() //获取队头元素 可读可修改{return _con.front();}const T& front()const  //获取队头元素 只可读不可修改{return _con.front();}T& back()  //获取队尾元素{return _con.back();}const T& back()const //获取队尾元素 只可读不可修改{return _con.back();}bool empty()const  //判断队列是否为空{return _con.empty();}size_t size()const  //获取队列中元素的总个数{return _con.size();}private:Container _con; //底层容器创建的对象
};

priority_queue

定义

在这里插入图片描述

  • priority_queue为优先队列,是容器适配器,默认情况下元素呈降序排列,且它的第一个元素总是它所有元素中最大的。
  • 容器适配器是将特定的类进行封装,将其作为该容器的底层容器,通过调用底层容器提供的一系列成员函数来实现该容器。元素从优先队列的顶部弹出。
  • priority_queue的底层容器既可以是某些标准容器类模板(vector、deque),也可以是其他特定的容器类,它必须支持以下操作:push_back()->插入元素、pop_back()->删除元素、front()->获取优先队列顶部的元素、empty()->判断优先队列是否为空、size()->获取优先队列中元素总个数。
  • priority_queue底层容器可以是vector、deque,但不可以是list(不支持随机访问[]),若未实例化指定特定的底层容器,则默认为vector。
  • priority_queue底层结构为堆,所有需要用到堆的地方,都可以考虑使用priority_queue。默认情况下为大堆,即小于less-》降序(大堆),greater-》升序(小堆)。
  • priority_queue底层容器要支持随机访问,以保持堆的结构。在堆中可以随时插入数据,且只检索到最大元素(大堆)或者最小元素(小堆)。
template<class T, class Container = vector<T>, class Compare = less<T>>
class priority_queue {private:Container _con;Compare _com;
};

priority_queue模拟实现

在这里插入图片描述

💡void push(const T& val) ;

  • 方法: 在堆的底部插入元素,在采用向上调整法

在这里插入图片描述

💡void pop( )

  • 方法: 堆顶元素和堆中最后一个元素交换,在删除最后一个元素,在采用向下调整法

在这里插入图片描述

//仿函数:功能像函数,但它就是个类模板,重载了operator(),通过将其设置为类模板参数,在其他类中通过该参数创造出对象,直接()调用
template<class T> //设计为类模板,泛型编程,是为了支持所有数据类型的比较
class less {  //小于
public:bool operator()(int x, int y){return x < y;}
};template<class T>
class greater { //大于
public:bool operator()(int x, int y){return x > y;}
};template<class T, class Container = vector<T>, class Compare = less<T>>
class priority_queue {//默认为大堆,且底层容器为vector
public:priority_queue()  //构造空优先队列{ }void Adjust_up(int child)  //向上调整法{int parent = (child - 1) / 2;while (child > 0){if (_com(_con[parent], _con[child])) {std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}elsebreak;}}void Adjust_down(int parent) //向下调整法{ //找到左、右孩纸中最大一个 -》假设法,假设左孩纸大,在与右孩纸进行比较int child = parent * 2 + 1;  if (child + 1 < _con.size() && _com(_con[child], _con[child + 1]))++child;while (child < _con.size()) {if (_com(_con[parent] ,_con[child])) // 默认情况下为大堆,大的优先级高{std::swap(_con[child], _con[parent]);parent = child;child = parent + 1;}elsebreak;  //前提:该堆已经是个大堆(小堆)了}}void pop() //堆顶元素和堆中最后一个元素交换,在删除最后一个元素,在采用向下调整法{std::swap(_con[0], _con[size() - 1]);_con.pop_back();Adjust_down(0);}void push(const T& val) //在堆的底部插入元素,在采用向上调整法{_con.push_back(val); Adjust_up(size() - 1);}const T& top()const //获取优先队列中顶部元素,即:堆顶元素{return _con.front();}bool empty()const  //判断优先队列是否为空{return _con.empty();}int size()const  //获取优先队列中总元素个数{return _con.size();}private:Container _con;  //底层容器创建的对象Compare _com;  //仿函数类创建的对象
};

deque

定义

  • deque是双端队列,是一种双开口的“连续”空间的数据结构,可以在头尾进行插入和删除操作,时间复杂度为O(1),与vector相比,头插效率高,不需要挪动数据,与list相比,空间利用率高,缓存命中率高。
  • deque实际上并不是连续的空间,而是由一段段连续的小空间拼接而成,为了维护其"整体的连续"以及随机访问。deque底层类似于动态二维数组。
    在这里插入图片描述

底层分析

在这里插入图片描述在这里插入图片描述

  • 与list相比 ,缓存命中率高,空间利用率高,因为deque底层空间连续。deque支持随机访问。
  • 与vector相比 ,对于在头、尾部插入和删除上,效率高于vector,因为不需要挪动数据。对于在扩容消耗上,效率高于vector,因为不需要频繁挪动数据,只要"中控"满了扩容就可以了,且只需要拷贝指针(4个字节)。
  • stack和deque为容器适配器,不需要遍历数据,所以它们没有迭代器,只需要在固定一端或者两端进行插入和删除数据。在插入元素时,deque效率高于vector(扩容消耗小),相比于list,deque不仅头、尾插效率高,且内存利用率高。综上所述,选择deque作为stack和deque默认的底层容器更有优势。

容器适配器

定义

  • 适配器是一种设计模式,该模式是将一种接口转换成另一种接口。
  • 容器适配器是一个对特定的类进行封装的类模板,它在底层容器的基础上提供了一些其他的功能。它是适配其他容器来提供不同的功能,通过调用底层容器提供的一系列成员函数来实现我们需要的功能。
  • stack和queue都可以存储元素,但未将他们划分到容器序列,而是将他们称为容器适配器,是因为stack和queue是对其他容器进行了封装,默认情况下,stack和queue的底层容器为deque。
    在这里插入图片描述
  • 💡Tips : 容器适配器中不存在迭代器。

种类

三种容器适配器:stack、queue、priority_queue。

在这里插入图片描述

仿函数

  • 💡仿函数:又称为函数对象,是一个重载了operator()运算符的类。
  • 仿函数,不是函数,在语法上与普通函数调用的语法调用一样,在功能上仿函数通过创建的对象去调用operator()运算符,从而达到函数一样的功能。
//仿函数
template<class T>
class less { //小于
public:bool operator()(int x, int y){return x < y;}
};template<class T>
class greater {  //大于
public:bool operator()(int x, int y){return x > y;}
};
void test()
{less<int> LessFu;cout << LessFu(3, 4) << endl;greater<int> GreaterFu;cout << GreaterFu(3, 4) << endl;
}int main()
{test();return 0;
}

在这里插入图片描述

控制类里面数据的比较逻辑

回调函数

  • 回调函数就是一个通过函数指针调用的函数。如果你把函数的地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说被调用的函数称为回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
namespace yun {bool Less(int x, int y){return x < y;
}bool Greater(int x, int y){return x > y;}//在A这个类中调用class A1 {public:A1(bool(*pf)(int, int)):_pf(pf){ }void fun(int x, int y){cout << _pf(x, y) << endl;  //回调函数}bool(*_pf)(int, int);};//通过回调函数去调用:缺点-》函数指针类型抒写太复杂、需要通构构造函数参数传递(成员变量_pf为虚拟指针,无值)void test1(){A1 aa1(Less); aa1.fun(3, 4);A1 aa2(Greater);aa2.fun(3, 4);}
}int main()
{yun::test1();  //回调函数return 0;
}

在这里插入图片描述

仿函数

namespace yun {//仿函数template<class T>class less { //小于public:bool operator()(int x, int y){return x < y;}};template<class T>class greater {  //大于public:bool operator()(int x, int y){return x > y;}};template<class T, class Compare = less<T>> class A2{  public:void fun(int x, int y){cout << _com(x, y) << endl;  //调用仿函数,实际上就是通过类对象去调用operator()运算符}private:Compare _com; //创建仿函数对象};void test2() {A2<int, less<int>> aa2;aa2.fun(5, 6);A2<int, greater<int>> aa3;aa3.fun(5, 6);}
}int main()
{yun::test2();  //仿函数return 0;
}

在这里插入图片描述

两者区别

  • 回调函数缺点:函数指针类型相对比较复杂、只能通过函数参数传递(在类中,通过构造函数参数传递,且需要定义函数指针类型的成员变量,进行值的接收,从而实现回调。在普通函数中,通过函数参数直接传递)。
  • 仿函数优点:类型相对比较简单、只需要在类中创建对象,通过该对象去调用operator()运算符,就可以实现回调。

铁铁们,就到此结束啦,若博主有不好的地方,请指正,欢迎铁铁们留言,请动动你们的手给作者点个👍鼓励吧,你们的鼓励就是我的动力✨

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

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

相关文章

移动端使用 echarts中 滚动条 dataZoom 改造为内容区域可以左右滚动

移动端使用 echarts中 滚动条 dataZoom 改造为内容区域可以左右滚动 直接上图 &#xff1a; 主要是下面这段代码&#xff1a; "dataZoom": [{"type": "inside","show": false,"xAxisIndex": [0],"zoomOnMouseWheel&…

Clickhouse 单机部署安装

前言 在大数据的时代背景下&#xff0c;数据的处理和分析能力成为企业竞争力的关键。ClickHouse&#xff0c;作为一款由俄国Yandex公司开发的分布式数据分析型数据库&#xff0c;凭借其卓越的性能和稳定性&#xff0c;赢得了业界的广泛关注。本文将介绍ClickHouse的基本概念、…

Qt/QML编程之路:基于QWidget编程及各种2D/3D/PIC绘制的示例(45)

关于使用GWidget,这里有一个示例,看了之后很多图形绘制,控件使用,及最基本的QWidget编程都比较清楚了。ui的绘制: 运行后的界面如 工程中有非常丰富的关于各种图形的绘制,比如上图中circle,还有image。有下面一段readme的说明: # EasyQPainter Various operation pra…

回到街头 - 数字时尚嘉年华:Web3的时尚未来,4月香港兰桂坊盛大启幕

随着区块链技术的不断发展&#xff0c;Web3世界正在逐渐改变我们的生活方式。作为这一变革的重要推动者&#xff0c;Vertex Labs荣幸地宣布&#xff0c;将在香港举办一场前所未有的“回到街头-数字时尚嘉年华”。这不仅是一场时尚与科技的完美结合&#xff0c;更是全球顶级IP和…

Linux arrch64系统架构 py文件运行时的编码问题解决

问题&#xff1a; 因为要测试一些东西&#xff0c;所以必须有中文数据来做支撑&#xff0c;之前用的架构是x86&#xff0c;现在一个服务器的架构为arrch64&#xff0c;下列编码都挨个都进行声明&#xff0c;但是无法解决问题&#xff0c;总是报错 # -*- coding: gbk -*- # -*…

考研数学——高数:高斯公式

助记: 关于积分时什么时候可以将变量整体代入积分式的问题&#xff1a;在积分过程中&#xff0c;如果某一整体恒为常量&#xff0c;则可以直接替换为定值&#xff0c;常见于对线或面的积分。 而在这题&#xff0c;用高斯公式之前是面积分&#xff0c;如果有这个整体出现的话是…

党费收缴管理系统(十八)关于支付total和payer_total差异的情况处理

在前面我们将支付回调通知解密获取出来的数据 &#xff0c;amount中有payer_total 和total两个值&#xff0c;正常情况下&#xff0c;这两个值应该是保持一致的。如果这两个值不一样&#xff0c;那么多半是党员缴纳过程使用了支付优惠券。 "amount":{"payer_t…

什么是VPS?如何使用VPS?

什么是VPS&#xff1f;VPS有什么用&#xff1f; VPS是Virtual Private Server的缩写&#xff0c;中文则为虚拟专用服务器&#xff0c;VPS是利用虚拟服务器软件在一台物理服务器上创建多个相互隔离的小服务器&#xff0c;是托管在机房物理服务器上的虚拟机。每个VPS服务器都可分…

Figure与OpenAI 联手推出新机器人;荣耀首款「AI PC」即将发布

▶ Figure 与 OpenAI 联手推出新机器人 AI 机器人公司 Figure 发布了他们与 OpenAI 的合作成果&#xff0c;将 OpenAI 的大模型运用在其机器人 Figure 01 上。 据介绍&#xff0c;OpenAI 大模型加持的 Figure 01 机器人现在可以与人全面对话。 OpenAI 模型为机器人提供了高级…

C# Onnx C2PNet 图像去雾 室内场景

目录 介绍 效果 模型信息 项目 代码 下载 C# Onnx C2PNet 图像去雾 室内场景 介绍 github地址&#xff1a;GitHub - YuZheng9/C2PNet: [CVPR 2023] Curricular Contrastive Regularization for Physics-aware Single Image Dehazing [CVPR 2023] Curricular Contrasti…

【蓝桥杯-单片机】基础模块:数码管

文章目录 【蓝桥杯-单片机】基础模块&#xff1a;数码管01 数码管原理图什么是位选和段选共阳极数码管和共阴极数码管的区分&#xff08;1&#xff09;共阳极数码管&#xff08;Common Anode&#xff09;&#xff1a;&#xff08;2&#xff09;共阴极数码管&#xff08;Common …

mac输入su命令报错如何重置密码

diannao1xiejiandeMacBook-Air ~ % su Password: su: Sorry输入 sudo passwd 命令重置密码即可。

【兔子机器人】实现从初始状态到站立

一、遥想星空up主的方法 由于我有卡位结构&#xff0c;无法做到劈腿&#xff0c;而且底盘也不一样&#xff0c;无法使用此方法 但是其代码思想是可以借鉴的。 参考视频&#xff1a; 【【开源啦&#xff01;】无刷轮腿平衡机器人】 【精准空降到 01:16】 https://www.bilibili…

LLM - 大语言模型的自注意力(Self-Attention)机制基础 概述

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/136623432 注意力(Attention)机制是大型语言模型中的一个重要组成部分&#xff0c;帮助模型决定在处理信息时&#xff0c;所应该关注的部…

52、WEB攻防——通用漏洞弱口令安全服务协议web应用

文章目录 web类——加密&验证码后台服务类——SSH&RDP远程终端猜解应用类——zip&word文件压缩猜解 弱口令没有严格的定义&#xff0c;通常认为容易被别人猜测到或被破解工具破解的口令均为弱口令&#xff0c;通常与管理的安全意识和平台的初始化配置等相关&#x…

LeetCode.2864. 最大二进制奇数

题目 2864. 最大二进制奇数 分析 这道题目其实我们只需要保证最后一位是1&#xff0c;其余的1都放在最前面&#xff0c;这样得到的就是最大二进制奇数。 所以&#xff0c;我们先统计给定的字符串有多少个 1&#xff0c;多少个 0&#xff0c;把其中一个 1 放在最后一位&…

LORA_ LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS

paper: https://arxiv.org/pdf/2106.09685.pdf code: https://github.com/microsoft/LoRA 摘要 作者提出了低秩自适应&#xff0c;或称LoRA&#xff0c;它冻结了预先训练的模型权值&#xff0c;并将可训练的秩分解矩阵注入变压器架构的每一层&#xff0c;大大减少了下游任务的…

Python爬虫实战入门:豆瓣电影Top250(保你会,不会来打我)

文章目录 需求所需第三方库requests模块lxml模块了解 lxml模块和xpath语法xpath语法-基础节点选择语法 实战教程完整代码 需求 目标网站: https://movie.douban.com/top250 需求: 爬取电影中文名、英文名、电影详情页链接、导演、主演、上映年份、国籍、类型、评分、评分人数, …

AIGC笔记--关节点6D位姿按比例融合

1--核心代码 6D位姿一般指平移向量和旋转向量&#xff0c;Maya软件中关节点的6D位姿指的是相对平移向量和欧拉旋转向量&#xff1b; 为了按比例融合两个Pose&#xff0c;首先需要将欧拉旋转向量转换为旋转矩阵&#xff0c;在将旋转矩阵转换为四元数&#xff0c;利用球面线性插值…

springboot项目自定义切面增强方法功能(springboot记录日志)

说明 背景&#xff1a;记录系统接口日志入库&#xff0c;包含接口方法、入参、回参、响应时间、操作人、操作时间等信息。 方案&#xff1a;添加自定义切面处理 一、自定义切面注解 package com.gstanzer.supervise.annotation;import com.gstanzer.supervise.enums.Busine…