stack、queue、priority_queue以及仿函数

我们上次对std中的list进行实现,今天我们要实现stack、queue、priority_queue以及仿函数。

目录

  • stack堆
    • 堆的框架
    • 构造函数
    • push插入
    • pop删除
    • size()大小
    • empty()判断空
    • top()取栈顶的元素
  • queue队列
    • 队列框架
      • 问题: 这里我们为什么用deque?
    • 插入
    • 删除
    • 取头数据
    • 取尾数据
    • 判断空和大小
  • priority_queue堆
    • priority_queue的架构
      • empty()判断空
      • size()大小
      • top()取堆顶元素
      • sawp()交换
      • push()插入
      • pop()删除
    • 仿函数
      • 仿函数架构

stack堆

堆的原则就是先进后出,后进先出。如图:
在这里插入图片描述

从上图我们可以看出来stack准确说就是一个vector,所以我们就可以利用vector来建。

堆的框架

既然是实现STL库,一定是相似与库中,我们先不看他用的是谁,我们刚刚也分析了用vector来实现,所以我们可以用vector来封装。
在这里插入图片描述
这里的Con表示Container(容器),我们只需要传一个容器类型就可以,这里用vector是因为stack的特性,也可以用deque(他是链表与顺序表的结合,这里不会多说)。

    template<class T, class Con = vector<T>>class stack{public:private:Con _c;};

构造函数

没错,你没看错,这里我们的构造函数什么都没有写,其实你不写构造函数也可以,我们也说了构造函数对内置类型不做处理,但是对内置类型会去调用它的默认构造,这里我们用了container容器,我们传什么容器类型就是什么容器,我们就可以间接区调用它的构造函数

stack()
{}

push插入

push其实很简单,vector中插入数据是不是用的push_back();那么我们可以调用那个成员函数,来达到插入效果。
在这里插入图片描述

 void push(const T& x){_c.push_back(x);}

pop删除

pop也是一样的。复用接口。因为我们是后进的先出,所以我们就尾删。

       void pop(){_c.pop_back();}

size()大小

 size_t size()const{return _c.size();}

empty()判断空

bool empty()const
{return  _c.empty();
}

top()取栈顶的元素

那么什么是栈顶呢?如果数据1的位置是0,那么数据3的位置一定是n-1,所以我们有了size就可以,用size()-1;而且vector支持下标。
在这里插入图片描述

  T& top(){return _c[size() - 1];}

queue队列

队列的特性是先进先出,后进后出
在这里插入图片描述

队列框架

其实队列和栈的框架是一样的。

template<class T, class Con = deque<T>>class queue{public:private:Con _c;};

问题: 这里我们为什么用deque?

因为头删问题,我们也知道头删vector是效率很低的,你会说为什么不用list,list不支持下标访问,但是这里用deque就能很好的避免,因为库中deque既有头删,也可以下标访问
在这里插入图片描述

deque的结构其实就是链表和vector的结合。但是deque的缺点也很致命。

  • deque的优点
    ①.头插尾插很快,不需要挪数据,只需要开空间插入
    ②支持连续访问
  • deque的缺点
    ①.中间的插入删除效率麻烦且一般。
    ②.方括号的效率并不极致。

插入

void push(const T& x)
{_c.push_back(x);
}

删除

void pop()
{_c.pop_front();
}

取头数据

 T& front(){return _c.front();}const T& front()const{return _c.front();}

取尾数据

        T& back(){return _c.back();}const T& back()const{return _c.back();}

判断空和大小

  size_t size()const{return   _c.size();}bool empty()const{return  _c.empty();}

priority_queue堆

优先级队列和队列没有任何关系!优先级队列是堆,并且他默认是大堆!我们看库中会发现,他和queue共用一个头文件。
在这里插入图片描述

我们在看一下库中的实现。有模板参数有 T、Container、那么Compare是啥啊?我们先不管,看库的时候,遇到不懂得,我们可以先往下看看,如果不影响我们就先不看他,所以我们先排除Compare。先把架子搭出来。
在这里插入图片描述

priority_queue的架构

我们还是复用容器类型,堆是完全二叉树,并且之前我们用vector就可以,通过上下调整位置,达到堆。

template<class T ,class Container=vector<T>, class Compare = less<T> >
class priority_queue
{
public:private:Container _con;
};

在这里插入图片描述

empty()判断空

我们从上图可以看出来priority_queue的成员函数并不多。

bool empty() const
{return _con.empty();
}	

size()大小

size_t size() const
{return _con.size();
}

top()取堆顶元素

堆顶元素是谁?是不是root根啊,我们用的也是vector,所以堆顶很好取。

T& top() 
{return _con[0];
}

sawp()交换

	void swap(T& p1,T&p2){std::swap(p1,p2);}

push()插入

我们之前学习堆的时候插入是怎么插入的?插到尾部,然后不断向上调整。如图,默认是大堆,我们在尾巴插入一个20,向上调整。通过父子对比,孩子比父亲大,我们就向上调整。
在这里插入图片描述

		void push(const T& x){//尾插然后向上调整_con.push_back(x);AdjustUp(size()-1);}void AdjustUp(int child){//Compare c;int parent = (child - 1) / 2;//找父亲while (child > 0){//不断调整,直到不满足要求了,结束//if (_con[child] > _con[parent])//if (c(_con[parent], _con[child]))if (_con[parent]<_con[child]){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}elsebreak;}}

pop()删除

库中说从顶部移除元素,所以我们需要删除堆顶。删除堆顶元素,我们可以首尾交换,然后尾删,向下调整
在这里插入图片描述
如图:
在这里插入图片描述

void pop()
{//头尾交换,删除,然后向下调整swap(_con[0], _con[size() - 1]);_con.pop_back();AdjustDown(0);
}
void AdjustDown(int parent)
{//Compare c;int child = parent * 2 + 1;while (child < size()){if (child < size() - 1 && _con[child] < _con[child + 1])//if (child < size() - 1 && c(_con[child], _con[child + 1])){//这里需要判断一下,因为我们找的都是左子树,判断一下右子树是否存在//如果存在,在判断一下那个大,哪个大就和哪个换。(默认大堆)child++;}if (_con[parent] < _con[child])//if (c(_con[parent], _con[child])){swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}elsebreak;}
}

仿函数

上述我们只能实现默认的大堆,现在如果我希望你实现一个小堆,你怎么办?ok,你会说我修改一下大于小于号,那么如果在实战的项目中,让你实现,你会和客户说等我一下,我修改一下大于小于号?那不可能,那怎么做呢?仿函数!

其实我们也见过仿函数,在排序中,我们可以利用仿函数排升序降序。
在这里插入图片描述
如果你在C语言阶段用过排序qsort();里面是不是会让你们传一个函数指针类型?其实仿函数就是解决了回调函数问题(函数指针)。

仿函数架构

其实在我们上面写priority_queue的时候,你会发现默认给的less却是大堆,这个我也不知道为什么,记住就好了。其实仿函数,你可以理解为,只要重载了operator() 就算是仿函数
你看输出的时候,是不是特别像一个函数?其实并不是的,其实只是重载了小括号。
在这里插入图片描述

	template<class T>class less{//控制大堆public:bool operator()( const T& x,const T&y){return x < y;}};template<class T>class greater{//控制小堆public:bool operator()(const T& x, const T& y){return x > y;}};template<class T ,class Container=vector<T>, class Compare = less<T> >class priority_queue{public:void push(const T& x){//尾插然后向上调整_con.push_back(x);AdjustUp(size()-1);}void pop(){//头尾交换,删除,然后向下调整swap(_con[0], _con[size() - 1]);_con.pop_back();AdjustDown(0);}private:void AdjustDown(int parent){Compare c;int child = parent * 2 + 1;while (child < size()){//if (child < size() - 1 && _con[child] < _con[child + 1])if (child < size() - 1 && c(_con[child], _con[child + 1])){child++;}//if (_con[parent] < _con[child])if (c(_con[parent], _con[child])){swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}elsebreak;}}void AdjustUp(int child){Compare c;//创建比较的对象int parent = (child - 1) / 2;while (child > 0){//if (_con[child] > _con[parent])//if (_con[parent]<_con[child])if (c(_con[parent], _con[child]))//传哪个仿函数调哪个{swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}elsebreak;}}Container _con;};

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

渲染农场是什么意思?瑞云渲染为你解答

渲染农场是一种通过集合多台计算机的计算能力来加速图像渲染过程的系统。它尤其适用于动画、电影特效和高端视觉效果的制作&#xff0c;这些领域通常需要处理非常复杂和计算密集型的渲染任务。 渲染农场就是一大群电脑&#xff0c;他们一起可以快速渲染出漂亮的图像。在做动画片…

无代码无国界:我们正在走向软件安全的狂野西部吗?

我们使用的几乎所有东西都是基于代码构建的&#xff0c;从汽车到智能冰箱再到门铃。在企业中&#xff0c;无数的应用程序保持设备、工作流程和操作的运行。因此&#xff0c;当早期的无代码开发平台于 2010 年推出时&#xff0c;承诺为公民开发人员提供更易于访问的应用程序开发…

CDGA|揭秘移动物联网数据治理秘诀,轻松提升数据质量,赋能智慧未来

在数字化浪潮汹涌的今天&#xff0c;移动物联网作为连接物理世界与数字世界的桥梁&#xff0c;其数据治理的重要性日益凸显。高质量的数据不仅是企业决策的基石&#xff0c;更是推动行业智能化、精细化发展的关键。本文将为您揭秘移动物联网数据治理的技巧&#xff0c;助您轻松…

通俗理解向量:从One-hot 到词嵌入

在NLP任务中&#xff0c;将文本转换为向量是一个必要的步骤&#xff0c;这个过程被称为词嵌入。 很多同学在学习过程中&#xff0c;对向量这一概念很模糊&#xff0c;或者无法理解&#xff1a;为什么要把一个单独的token&#xff0c;或者一个数字&#xff0c;在转换为复杂的向…

2024最新互联网公司工作时长排行榜出炉!

“工作时长”&#xff0c;是选择公司的一个非常重要的参考指标。 我们在选择一个公司的时候&#xff0c;除了需要关注总收入package 以外&#xff0c;还需要考虑这家公司的加班时长是否人性化。 我们的工作时长是周工作小时数。法定工作时间是40小时(955)。大小周通常折算为周…

【OceanBase诊断调优】—— 备份恢复如何定位 NFS 服务异常

当备份、归档出现异常时&#xff0c;我们应该首先排除备份介质、网络是否正常&#xff0c;本文讲述如何通过系统表和日志来定位 NFS 服务异常。 适用版本 OceanBase 数据库所有版本。 如何查看备份归档异常&#xff1f; 查看备份归档状态表&#xff0c;MAX_NEXT_TIME 应与当…

C# WinForm —— 21 RichTextBox 使用

1. 加载文件到控件中 加载文件时&#xff0c;要设置文件的路径和类型RichTextBoxStreamType&#xff0c;文件类型包含&#xff1a; RichText 0&#xff1a;富文本格式&#xff08;RTF&#xff09;流PlainText 1&#xff1a;纯文本流对象链接和嵌入&#xff08;OLE&#xff…

LVM - Linux磁盘逻辑卷管理器概念讲解、实践及所遇到的问题

1、lvm概念 逻辑卷管理器(LogicalVolumeManager)本质上是一个虚拟设备驱动,是在内核中块设备和物理设备之间添加的一个新的抽象层次,它可以将几块磁盘(物理卷,PhysicalVolume)组合起来形成一个存储池或者卷组(VolumeGroup)。LVM可以每次从卷组中划分出不同大小的逻辑卷(Logi…

2024年网络安全威胁

随着2024年的到来&#xff0c;数字世界的版图正在以前所未有的速度扩张&#xff0c;引领我们进入一个技术革新的新时代。然而&#xff0c;这飞速的发展同时也催生了一系列错综复杂的网络安全挑战。在这个数字平台与我们生活日益紧密交织的时代&#xff0c;深入了解这些新兴的威…

云服务器和物理机该怎样分别呢

随着网络的不断发展&#xff0c;服务器的类型也在以不同的方式更新。现在云服务器的兴起占据了很大一部分市场&#xff0c;物理机的市场份额受到了很大的冲击。物理机和云服务器有什么区别&#xff1f;如何选择适合自己需求的&#xff1f;虽然物理服务器和云服务器都是服务器&a…

使用VMware或VirtualBox安装eNSP Pro并使用CRT连接设备

文章目录 使用Oracle Virtual Box安装eNSP Pro创建虚拟机配置网卡配置带外管理网络 使用VMware Workstation安装eNSP Pro转换文件格式及虚拟磁盘模式配置网卡创建虚拟机配置使用CRT连接管理设备 前一段时间是开放了eNSP Pro的账号权限&#xff0c;但是在写博客时&#xff0c;权…

【qt】一次性讲清楚日期和时间

时间日期 一.QTime类1.初始化2.获取当前时间3.获取 小时 分钟 秒 毫秒4.增加时间5.间隔时间6.字符串转时间7.时间转字符串 二.QDate类1.初始化2.获取当前日期3.设置日期4.获取 年 月 日5.各种小接口6.增加日期7.日期间隔8.字符串转日期9.日期转字符串 三.QDateTime类1.初始化2.…

安卓Fragment基础

目录 前言一、基础使用二、动态添加Fragment三、Fragment的生命周期四、Fragment之间进行通信五、Fragment兼容手机和平板示例 前言 Fragment基础使用笔记 一、基础使用 Activity布局和文件 <LinearLayout xmlns:android"http://schemas.android.com/apk/res/andro…

前端面试题(二十三)(答案版)

面试形式&#xff1a;线上电话面试&#xff1a;一面&#xff1a;时长30分钟 面试评价&#xff1a;精准考察项目所需技术理论工作实践 面试官的提问大纲&#xff1a;本公司项目要求本人简历 工作经验&#xff1a;2-4年 公司名称&#xff1a;深圳XX&#xff08;想知道的就滴喔…

KNN算法项目实战之酒的分类

加载数据集 from sklearn.datasets import load_winewine_dataset load_wine()数据集有什么&#xff1f; data&#xff1a;数据 target&#xff1a;目标分类 target_names&#xff1a;目标分类名称 DESCR&#xff1a;数据描述 features_names&#xff1a;特征变量名称 查…

2024自学网络安全的三个必经阶段(含路线图)_网络安全自学路线

一、为什么选择网络安全&#xff1f; 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护2.0》等一系列政策/法规/标准的持续落地&#xff0c;网络安全行业地位、薪资随之水涨船高。 未来3-5年&#xff0c;是安全行业的黄金发展期&#xff0c;提前踏入…

从零入门激光SLAM(十六)——卡尔曼滤波基础

一、卡尔曼滤波简介KF 卡尔曼滤波器&#xff08;Kalman Filter&#xff09;是一种用于估计动态系统状态的递归算法。它通过结合系统的动态模型和噪声观测数据&#xff0c;提供对系统状态的最优估计。卡尔曼滤波器广泛应用于信号处理、控制系统、导航、计算机视觉等领域。 卡尔…

SHELL编程(一)

目录 一、 Linux操作系统&#xff08;一&#xff09;内核与操作系统&#xff08;二&#xff09;操作系统的功能 二、Linux高级命令&#xff08;一&#xff09; 离线安装 dpkg1. 安装2. 使用3. 查看安装详细信息4. 安装路径5. 不完全删除6. 完全删除 &#xff08;二&#xff09;…

买了个彩票,哈哈哈哈哈。

买了个彩票-双色球&#xff0c;发现挺有意思的。 索性把双色球的所有期的中奖号码的数据都爬了下来&#xff0c;03至今&#xff0c;21年了。txt文本&#xff0c;6.5MB大小。 大家有啥好的建议&#xff0c;分析一下数据呢。

数据结构链表详解(不仅顺序表可以,我链表也可以)

目录 顺序表的缺点&#xff1a; 链表 链表的概念及其结构 链表的分类 链表的实现 链表形式&#xff1a; 节点的创建: 链表的增删&#xff1a; 尾插 头插 尾删 头删 查找 打印 链表的重点 1、尾删&#xff1a;则是需要找到尾节点&#xff0c;进行删除 2、头删&a…