【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.hqwc.cn/news/540210.html

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

相关文章

Android的三种动画详解(帧动画,View动画,属性动画)

Android的三种动画详解&#xff08;帧动画、View动画、属性动画&#xff09;_android动画效果大全-CSDN博客 1、帧动画 缺点是&#xff1a;占用内存较高&#xff0c;播放的是一帧一帧的图片&#xff0c;很少使用。 顺序播放预先定义的图片&#xff0c;类似于播放视频。 步骤…

WPS 相较于其他办公软件有哪些优势?

WPS Office 是一款流行的办公软件套件&#xff0c;与其他办公软件相比&#xff0c;它具有以下优势&#xff1a; 1. **兼容性强**&#xff1a;WPS Office 可以很好地与 Microsoft Office 兼容&#xff0c;能够打开、编辑和保存 Microsoft Office 格式的文档&#xff0c;如 Word…

生成器模式(软考uml C++版)

按照软考中级软件设计师中指定的生成器模式uml图&#xff0c;可编写对应的C&#xff0b;&#xff0b;代码&#xff1a; #include<iostream> #include<vector> #include<string> using namespace std;/*创建者模式&#xff0c;又名生成器模式意图&#xff1a…

中宣部防沉迷系统PHP版本(管局防沉迷验证-PHP-全版本-接口测试样例)

现在对接游戏&#xff0c;无论是登录还是支付都是要去对接防沉迷实名认证接口&#xff0c;但前期的话你要登录网络游戏防沉迷实名认证系统进行接口测试&#xff0c;$appid &#xff0c;$bizId&#xff0c;$key去接口测试页面找&#xff08;正式上线在密钥管理&#xff09;&…

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

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

【数据分析】数据分析介绍

专栏文章索引&#xff1a;【数据分析】专栏文章索引 目录 一、介绍 二、生活中的数据分析 1.无处不在的数据 2.为什么要进行数据分析&#xff1f; 三、数据挖掘案例 1.案例分析 一、介绍 数据采集&#xff1a;数据采集是指从不同来源收集原始数据的过程&#xff0c;包括…

Qt+FFmpeg+opengl从零制作视频播放器-3.解封装

解封装&#xff1a;如下图所示&#xff0c;就是将FLV、MKV、MP4等文件解封装为视频H.264或H.265压缩数据&#xff0c;音频MP3或AAC的压缩数据&#xff0c;下图为常用的基本操作。 ffmpeg使用解封装的基本流程如下&#xff1a; 在使用FFmpeg API之前&#xff0c;需要先注册API&a…

记某次HVV:文件上传打入内网

免责声明 本文仅用于参考和学习交流&#xff0c;对于使用本文所提供的信息所造成的任何直接或间接的后果和损失&#xff0c;使用者需自行承担责任。本文的作者对此不承担任何责任。请在使用本文内容时谨慎评估风险并做出独立判断。谢谢&#xff01; 前言 某次地市hvv发现一个…

2024三轮车行业发展现状

环洋市场咨询&#xff08;Global Info Research&#xff09;的三轮车市场调研报告提供三轮车市场的基本概况&#xff0c;包括定义&#xff0c;分类&#xff0c;应用和产业链结构&#xff0c;同时还讨论发展政策和计划以及制造流程和成本结构&#xff0c;分析三轮车市场的发展现…

Ubuntu系统的安装及基础操作

目录 一、VMware虚拟机安装Ubuntu20.04过程 1、安装前的准备工作 2、VMware虚拟机创建Ubuntu操作系统 步骤一&#xff1a;以管理员的身份运行VMware虚拟机 步骤二&#xff1a;新建虚拟机 步骤三&#xff1a;选择类型配置 步骤四&#xff1a;选择安装客户机操作系统 步骤…

PlayBook 详解

4&#xff09;Playbook 4.1&#xff09;Playbook 介绍 PlayBook 与 ad-hoc 相比&#xff0c;是一种完全不同的运用 Ansible 的方式&#xff0c;类似与 Saltstack 的 state 状态文件。ad-hoc 无法持久使用&#xff0c;PlayBook 可以持久使用。 PlayBook 剧本是 由一个或多个 “…

Jmeter入参问题小记

表单入参的时候&#xff0c;这个地方需要勾选&#xff0c;如果不☑️选的话&#xff0c;会提示errorMsg":"Required String parameter code is not present",