stack、queue、priority_queue以及仿函数

news2024/9/21 16:21:00

我们上次对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;
				}
				else
					break;

			}
		}

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;
		}
		else
			break;
	}
}

仿函数

上述我们只能实现默认的大堆,现在如果我希望你实现一个小堆,你怎么办?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;
				}
				else
					break;
			}
		}
		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;
				}
				else
					break;

			}
		}
		Container _con;
	};

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

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

相关文章

谷歌Google搜索广告开户流程与费用?

谷歌Google作为全球领先的搜索引擎&#xff0c;其广告平台——Google Ads&#xff0c;无疑是企业捕获潜在客户的黄金钥匙。想要在广阔的互联网海洋中精准航行&#xff0c;了解Google搜索广告的开户流程与费用至关重要。通过云衔科技的专业服务&#xff0c;让您的谷歌Google广告…

CST电磁仿真软件远场变更和结果相关【从入门到精通】

1、使用阵列系数计算阵列远场结果 对单一天线进行 仿真分析后&#xff0c;查看反映阵列系数的远场结果&#xff01; Navigation Tree > Farfields > Selection > Farfield Plot > Array Factor 下面介绍一下&#xff0c;对单一天线进行仿真后&#xff0c;轻松计…

【吃透Java手写】6-Netty-NIO-BIO-简易版

Netty 1 BIO&NIO模型 1.1 BIO 在JDK1.4出来之前&#xff0c;我们建立网络连接的时候采用BIO模式&#xff0c;需要先在服务端启动一个ServerSocket&#xff0c;然后在客户端启动Socket来对服务端进行通信&#xff0c;默认情况下服务端需要对每个请求建立一堆线程等待请求&…

暴利 选品大课:选品决定成败,教你多种大爆款选品方法(12节课)

课程目录 001.第一讲:选品决定成败.mp4 002.第二讲:选品也有生辰八字,mp4 003.第三讲:高热度选品底层逻辑,mp4 004,第四讲:高动销选品底层逻辑,mp4 005,第五讲:高点击选品底层逻辑,mp4 006.第六讲:高转化选品底层逻辑.mp4 007.第七讲:低付费选品底层逻辑.mp4 008,第八讲…

运维别卷系列 - 云原生监控平台 之 04.prometheus 查询语句 promql 实践

文章目录 [toc]PromQL 简介什么是时间序列 PromQL 数据类型即时向量 Instant vector范围向量 Range vectorTime DurationsOffset modifier modifier 浮点值 Scalar字符串 String PromQL FUNCTIONSfloor()irate()rate()round()sort()sort_desc() PromQL 运算符算术运算符比较运算…

web安全学习笔记(15)

记一下第25-26课的内容。弱口令爆破的四种模式与判断成功失败的三种方案&#xff1b;爆破中的验证码拦截错误次数IP限制密码加密绕过 IP获取的原理以及绕过CDN获取客户真实IP 一、弱口令的分类 1.常规弱口令&#xff1a;如123456&#xff0c;666666&#xff0c;888888等 2.…

网络安全等级保护在工业控制系统中的应用

工业控制系统(Industrial Control Systems,ICS)&#xff0c;是由各种自动化控制组件和实时数据采集、监测的过程控制组件共同构成。其组件包括数据采集与监控系统(SCADA)、分布式控制系统(DCS)、可编程逻辑控制器(PLC)、远程终端(RTU)、智能电子设备(IED)&#xff0c;以及确保各…

jspXMl标记语言基础

1.打开命令框进入数据库 打开eclipse创建需要连接的项目 粘贴驱动程序 查看驱动器 使用sql的包 int代表个 conlm代表列名 <%page import"java.sql.ResultSet"%> <%page import"java.sql.Statement"%> <%page import"java.sql.Connect…

Elasticsearch 实现word、pdf、txt、excel文档内容快速检索(保姆级教程)

本文主要讲解ES如何从提取文档中提取内容&#xff08;word、pdf、txt、excel等文件类型&#xff09;&#xff0c;实现快速检索文档内容实现。 特别说明一下&#xff0c;为什么用7.10.0版本&#xff0c;因为在项目中除了精确匹配的要求&#xff0c;也会有模糊查询&#xff08;关…

合并K个升序链表

题目 解法一 优先级队列 思想 将每个链表中的一个节点存放到优先级队列中&#xff0c;本题采用小根堆&#xff0c;将小根堆中的根节点取出&#xff0c;插入到最终的链表中&#xff0c;并且将该节点在原链表中的下一个节点插入小根堆中&#xff08;需要向下调整&#xff09;&a…

Day_5

1. Apache ECharts Apache ECharts 是一款基于 Javascript 的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表 官网地址&#xff1a;https://echarts.apache.org/zh/index.html 入门案例 快速入门&#x…

LearnOpenGL(十八)之面剔除

一、面剔除 对于一个3D立方体&#xff0c;无论我们从哪个方向&#xff0c;最多只能同时看到3个面。如果我们能够以某种方式丢弃另外几个看不见的面&#xff0c;我们就能省下超过50%的片段着色器执行数&#xff01; 这正是面剔除(Face Culling)所做的。OpenGL能够检查所有面向…

ClassificationPrimitive 内部原理

ClassificationPrimitive 内部原理 发明 ClassificationPrimitive的真是个天才。其原理是利用 webgl 的模板缓冲区实现。 渲染两次, 首先是绘制模板, 然后绘制真正的内容。 示意图: function createClass() {const { program, uniforms } WebGLProgram.buildPrograms(gl, …

PMR-440N7Q韩国施耐德三和相序继电器EOCR-PMR

韩国施耐德三和EOCR继电器PMR-440N7Q PMR-440-N 直流电动机保护器:DCL、DOCR-S/H 欠电流继电器:EUCR-3C 交流电压继电器:EOVR、EVR-PD、EVR-FD、EUVR 韩国三和EOCR电动机保护器:EOCR-SS、EOCR-SS1/SS2、EOCR-AR、EOCR-ST、EOCR-SP、EOCR-SP1/SP2、EOCR-SE、EOCR-SE2/SE PMR-44…

会员网站如何创建具有不同仪表盘结构的用户帐户页面

用户帐户页面是中央用户仪表盘&#xff0c;用户可以在其中添加和编辑信息、发布和编辑帖子以及保存收藏夹项目。本教程介绍如何使用“内容”和“重写”模板模式设置帐户页面、为帐户页面创建子页面以及设置个人资料菜单等。 在本教程中&#xff0c;我们将介绍如何使用招聘网站…

Netty的组件和设计

目录 Channel、EventLoop和ChannelFuture Channel接口 EventLoop接口 ChannelFuture接口 ChannelHandler和ChannelPipeline ChannelHandler接口 ChannelPipeline接口 更加深入地了解ChannelHandler 编码器和解码器 抽象类SimpleChannelInboundHandler 引导 从高层次…

vue网页端控制台展示独有标记

效果展示 实现步骤 1. 新建js文件 定义一个类 用于提供控制台打印日志显示样式的方法 src\libs\util.log.js class Logger {// 定义静态方法static typeColor(type "default") {let color "";switch (type) {case "default":color "#3…

Lambda 表达式详解

LAMBDA ⚪ λ 希腊字母表中排序第十一位的字母, 英语名称为Lambda ⚪ 避免匿名内部类定义过多 ⚪ 其实质属于函数式编程的概念 ⚪ 也可称为闭包 ⚪ Lambda允许把一个函数作为方法的参数&#xff08;函数作为参数传递进方法中&#xff09;。 Lambda是在jdk8之后出现的所以现…

Xed编辑器开发第一期:使用Rust从0到1写一个文本编辑器

这是一个使用Rust实现的轻量化文本编辑器。学过Rust的都知道&#xff0c;Rust 从入门到实践中间还隔着好几个Go语言的难度&#xff0c;因此&#xff0c;如果你也正在学习Rust,那么恭喜你&#xff0c;这个项目被你捡到了。本项目内容较多&#xff0c;大概会分三期左右陆续发布&a…

WebLogic SSL应用

SSL 安全套接字层(SSL)是通过在客户端和Web服务器端之间进行身份验证,并对双方交换的数据进行加密,从而提供安全连接。 验证类型: 单向:客户端验证Web服务器端证书 双向:客户端验证Web服务器证书, Web服务器验证客户端证书 Weblogic Server12c 支持 SSL 3.0 和 TLS1.0 …