C++ | 仿函数与priority_queue

news2024/11/25 14:02:24

目录

前言

一、初始仿函数

1、仿函数是什么

2、仿函数的使用 

二、优先级队列

1、 优先级队列的基本概念

2、堆的储存结构与结点之前关系

3、堆的使用

4、堆的模拟实现


前言

        本文主要介绍优先级队列与仿函数,优先级队列实际上是我们在数据结构中学的堆;在介绍优先级队列之前,我们必须的初步的认识学习一下什么叫仿函数,与仿函数的使用;

一、初始仿函数

1、仿函数是什么

        仿函数实际上是一个重载了()的类;仿函数也叫对象函数;我们通过对象访问成员函数的方式调用函数;与其相对的是C语言的函数指针,因为C语言的函数指针在某些情况下太过于复杂,于是C++设计出了仿函数;

2、仿函数的使用 

        我们通过一下代码来学习仿函数的定义与使用; 

#include <functional>
// 带模板参数的仿函数
template<class T>
struct Greater
{
	// 重载()
	bool operator()(const T& x, const T& y)
	{
		return x > y;
	}
};

void test_func()
{
	int x = 3;
	int y = 10;
	// 创建一个仿函数对象
	Greater<int> Gre;
	// 通过对象调用仿函数
	cout << Gre(x, y) << endl;
	// 通过匿名对象调用仿函数
	cout << Greater<int>()(x, y) << endl;
}
int main()
{
	test_func();
	return 0;
}

        我们通过重载对象里的圆括号,来实现用对象来模拟函数功能;而我们的优先级队列也巧妙的使用了仿函数,来实现通过模板参数控制我们实现的是大堆还是小堆;

二、优先级队列

1、 优先级队列的基本概念

        优先级队列在数据结构中又被称为堆,堆是一种完全二叉树结构;分为大堆与小堆;

大堆:父节点大于子节点

小堆:父节点小于父节点

        大小堆并没有要求左右孩子大小顺序,也就是说在任意堆中,左孩子可能大于右孩子,也可能小于右孩子;

2、堆的储存结构与结点之前关系

        一般情况下,我们用顺序结构储存堆,通过下标关系来定位孩子与父亲之间的关系;

父亲下标 = (孩子下标 - 1)/ 2

左孩子下标 = (父亲下标 * 2) + 1

右孩子下标 = (父亲下标 * 2) + 2

        我们可以通过下图尝试使用以上规则是否适用;

3、堆的使用

堆有如下几个接口;使用成本也不高;

void test_priority_queue()
{
	// 创建优先级队列
	std::priority_queue<int, vector<int>, greater<int>> pq;
	// 插入数据
	pq.push(13);
	pq.push(17);
	pq.push(23);
	pq.push(27);
	pq.push(33);
	pq.push(35);
	pq.push(43);
	pq.push(47);
	pq.push(54);
	pq.push(56);
	// 判空
	while (!pq.empty())
	{
		// 获得堆顶数据
		cout << pq.top() << " ";
		// 取出堆顶数据
		pq.pop();
	}
	cout << endl;

}

4、堆的模拟实现

        堆的模拟实现也不是很难,与前面的stack与queue一样,堆也是适配器容器,我们仅仅只需实现向上调整与向下调整两个接口即可,其他接口均复用;

#include <vector>
#include <functional>

namespace MySpace
{
	template<class T, class Container = std::vector<T>, class Compara = std::less<T>>
	class priority_queue
	{
	private:
		void adjust_up(size_t child)
		{
			// 计算父节点下标
			size_t parent = (child - 1) / 2;
			// 假若孩子结点已经为根节点了,则无法继续向上调整了
			while (child > 0)
			{
				// 通过仿函数比较父节点与子节点的大小关系
				if (Compara()(_con[parent], _con[child]))
				{
					// 条件满足,交换两个结点的值
					std::swap(_con[child], _con[parent]);
					// 计算下一个父节点,查看是否还需要向上调整
					child = parent;
					parent = (child - 1) / 2;
				}
				else // 否则退出循环,调整完毕
				{
					break;
				}
			}
		}
		void adjust_down(size_t parent)
		{
			// 计算孩子结点的下标
			size_t child = parent * 2 + 1;
			// 如果孩子结点大于最后一个数据的下一个位置的下标直接退出循环
			while (child < _con.size())
			{
				// 查看右孩子是否存在,若存在,是否比左孩子大或小
				if (child + 1 < _con.size() && Compara()(_con[child], _con[child + 1]))
				{
					child++;
				}
				// 拿大的(小的)那个孩子进行比较,查看是否需要交换
				if (Compara()(_con[parent], _con[child]))
				{
					// 交换父节点与子节点的数据
					std::swap(_con[child], _con[parent]);
					// 跟新父节点与子节点下标
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
	public:
		void push(const T& val)
		{
			_con.push_back(val);
			adjust_up(_con.size() - 1);
		}
		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
		const T& top() const
		{
			return _con.front();
		}
	private:
		Container _con;
	};

}

        在push函数中,我们插入一个数据会插入到尾部,此时我们需要向上调整,使堆重新恢复堆结构;

        我们结合前面的知识,计算出父节点的下标,依次通过仿函数比较是否需要进行调整数据;关于向下调整,具体思路也一样,代码有具体注释;

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

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

相关文章

02 | conda的使用

1 前提 Conda是一个在Windows、macOS、Linux和z/OS上运行的开源软件包管理系统和环境管理系统。Conda快速安装、运行和更新软件包及其依赖项。Conda可以在本地计算机上轻松创建、保存、加载和切换环境。它是为Python程序创建的&#xff0c;但它可以为任何语言打包和分发软件。…

Tomcat 8.5 源码分析

一、获取源码并启动程序 获取教程地址 总体架构 二、Tomcat的启动入口 Catalina类主要负责 具体的管理类&#xff0c;而Bootstrap类是启动的入口(main方法)。 /*** Main method and entry point when starting Tomcat via the provided* scripts.** param args Command lin…

C# Post 接口请求样例

很久没有写接口了&#xff0c;正好今天写到了接口&#xff0c;记录一下 封装Http Post请求&#xff0c;这里的请求头是 request.ContentType “application/json”; 复制后根据实际去修改&#xff0c;不要生搬硬套搞拿来主义&#xff1a; /// <summary>/// 发送http请求…

Spring Cloud 远程接口调用OpenFeign负载均衡实现原理详解

环境&#xff1a;Spring Cloud 2021.0.7 Spring Boot 2.7.12 配置依赖 maven依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency&…

什么是XSS攻击及其类型和危害

什么是XSS攻击及其类型和危害 跨站脚本攻击&#xff08;Cross-Site Scripting&#xff0c;简称 XSS&#xff09;是一种常见的网络安全漏洞&#xff0c;攻击者通过在受害者的浏览器中注入恶意脚本&#xff0c;从而在受害者的浏览器端执行恶意代码&#xff0c;从而实现攻击目的。…

在CSDN博客平台上吸引铁粉诀窍

&#x1f3c6;荣誉认证&#xff1a;51CTO博客专家博主、TOP红人、明日之星&#xff1b;阿里云开发者社区专家博主、技术博主、星级博主。 ⭐本文介绍⭐ 在社交媒体时代&#xff0c;拥有一批忠实的粉丝对于博主来说非常重要。这些铁粉不仅能够给予支持和鼓励&#xff0c;还能为…

第十八章 番外篇:混合精度训练

参考教程&#xff1a; https://pytorch.org/tutorials/recipes/recipes/amp_recipe.html?highlightamp https://pytorch.org/docs/stable/amp.html https://arxiv.org/pdf/1710.03740.pdf https://zhuanlan.zhihu.com/p/79887894 文章目录 原理float 32float 16混合精度 代码实…

cmake编译mingw下使用的zlib

目录 一、准备 二、cmake构建 三、make编译 一、准备 zlib Home Site zlib1.2.11&#xff08;2017.2.15&#xff09; 二、cmake构建 有cmakeLists.txt&#xff0c;直接用cmake进行构建 然后点击generate&#xff0c;接下来只能用命令行编译&#xff0c;在build目录执行…

选购螺杆支撑座要考虑哪些因素?

为了可以保证螺杆支撑座的使用效果&#xff0c;同时也能够发挥出更好的使用功能&#xff0c;避免出现各种质量隐患&#xff0c;建议大家在购买的时候一定要在专业正规的厂家进行选购&#xff0c;那么&#xff0c;我们在选购的时候要考虑哪些方面的因素呢&#xff1f; 1、考虑到…

曲柄滑块运动学求解基于Matlab

参考文档&#xff1a; 曲柄滑块机构运动分析..doc-原创力文档 偏置曲柄滑块机构的运动学分析 - 豆丁网 偏置式曲柄滑块机构仿真与运动分析 - 豆丁网 https://www.cnblogs.com/aksoam/p/17013811.html function main %输入已知数据 close all clear; i1100; i2300; e56; hd …

统一异常处理,自定义异常

目录 一、制造异常 Swagger中测试 二、统一异常处理 1、创建统一异常处理器 2、测试 三、处理特定异常 1、添加依赖 2、添加异常处理方法 3、测试 4、恢复制造的异常 四、自定义异常 1、创建自定义异常类 2、添加异常处理方法 3、修改Controller 4、测试 返回异…

3.1 Bootstrap 字体图标(Glyphicons)

文章目录 Bootstrap 字体图标(Glyphicons)什么是字体图标&#xff1f;获取字体图标CSS 规则解释带有导航栏的字体图标定制字体图标定制字体尺寸定制字体颜色应用文本阴影 Bootstrap 字体图标(Glyphicons) 本章将讲解字体图标(Glyphicons)&#xff0c;并通过一些实例了解它的使用…

【SpringBoot】SpringBoot的自动配置源码解析

文章目录 1. SpringBoot的自动配置概念2. SpringBoot自动配置的原理3. EnableAutoConfiguration4. 常用的Conditional注解 1. SpringBoot的自动配置概念 SpringBoot相对于SSM来说&#xff0c;主要的优点就是简化了配置&#xff0c;不再需要像SSM哪有写一堆的XML配置&#xff0…

SQLSERVER的truncate和delete有区别吗?

一&#xff1a;背景 1. 讲故事 在面试中我相信有很多朋友会被问到 truncate 和 delete 有什么区别 &#xff0c;这是一个很有意思的话题&#xff0c;本篇我就试着来回答一下&#xff0c;如果下次大家遇到这类问题&#xff0c;我的答案应该可以帮你成功度过吧。 二&#xff1…

全网最细,Pytest自动化框架fixture和conftest.py实战详解(细致)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 fixture说明 fix…

你一定不知道的自动化测试的9大规则

目录 前言 应该去做的事情 雇用合适的人 在寻找正确的测试自动化工具方面花点时间 轻装上阵 让开发人员参与到自动化过程中来 在ci/cd上投资时间 不应该做的事情 不要因为一个工具被追捧就选择它 不要试图将一切都自动化 不要太早实现自动化 永远不要用自动化来取代…

C语言-报错集锦-02-munmap_chunk(): invalid pointer: 0x0000000001d2e150 ***

一、报错信息 [2023-7]--[ Debug ]--Destroy DqlResult Struct OK [2023-7]--[ Debug ]--Destroy Moia Base Job : OK [2023-7]--[ Debug ]--Destroy Moia Base Job : OK [2023-7]--[ Debug ]--Destroy Moia Base Job : OK [2023-7]--[ Debug ]--Destroy Mo…

Redis学习(二)线程安全、分布式锁、消息队列

文章目录 优惠券秒杀全局ID生成器优惠券秒杀下单超卖问题一人一单 分布式锁基于Redis的setnx指令实现分布式锁解决锁误删问题基于Lua脚本实现多条指令原子性Redis调用Lua脚本Java中使用Lua脚本 RedissonRedisson快速入门Redisson可重入锁原理Redisson的锁重试和Watchdog机制Red…

【经济调度】基于多目标宇宙优化算法优化人工神经网络环境经济调度研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

适配各类大模型应用!手把手教你选择 Zilliz Cloud 实例类型

作为大模型时代备受关注的细分赛道&#xff0c;向量数据库可以不仅为大模型提供存储和向量检索的功能&#xff0c;还能适配各种 AI 应用场景&#xff0c;例如聊天机器人、内容审核、增强 LLM 知识库等。 不过&#xff0c;对于向量数据库的开发者而言&#xff0c;成本是绕不开的…