C++奇迹之旅:快速上手Priority_queue的使用与模拟实现

news2024/12/23 13:51:15

请添加图片描述

文章目录

  • 📝priority_queue的介绍和使用
  • 🌠 priority_queue的介绍
    • 🌉priority_queue的使用
  • 🌠仿函数的使用
  • 🌠C语言有趣的模仿push_back
  • 🌠priority_queue的模拟实现
  • 🚩总结


📝priority_queue的介绍和使用

🌠 priority_queue的介绍

priority_queue官方文档:https://legacy.cplusplus.com/reference/queue/priority_queue/?kw=priority_queue
在这里插入图片描述

  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中,位于顶部的元素)
  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素,元素从特定容器的尾部弹出,其称为优先队列的顶部。
  4. 底层容器可以是任意标准容器类模版,也可以是其他特定设计的容器类。容器应该可以随机访问迭代器访问,并支持以下的操作:
  • empty():检测容器是否为空
  • size():返回容器中有效元素个数
  • front():返回容器中第一个元素的引用
  • push_back():在容器尾部插入元素
  • pop_back():删除容器尾部元素
  1. 标准容器类vector和deque满足这些需求。默认情况下,如果没没有为特定的priority_queue类实例化指定容器类,则使用vector.
  2. 需要支持随机访问迭代器 ,以便始终在内部保持堆结构,容器适配器通过在需要时自动调用算法函数make_heap,push_heap,和pop_heap来完成自动操作

🌉priority_queue的使用

优先级队列默认使用vector作为其底层容器存储数据的容器,在vector上又使用堆算法讲vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的成员位置,都可以考虑使用priority_queue。
注意:默认情况下priority_queue是大堆

数说明接口说明
priority_queue()/priority_queue(first,last)构造空的栈
empty()J检测优先级队列是否为空,是返回true,否则返回false
size()返回元素的个数
top()返回优先级队列中最大(最小元素),即堆顶元素
push(x)在优先级队列中插入元素
pop()删除优先级队列中最大(最小)元素,即堆顶元素

需要注意的是:

  1. 默认情况下,priority_queue是大堆

在这里插入图片描述

在这里插入图片描述
如果需要要得到小堆,修改比较方式就好,比较方式可以有仿函数,函数指针,函数模板,类模版等等,
比如使用function文件的
在这里插入图片描述
在这里插入图片描述
正常来说,greate是用来降序,大根堆,这里跟往常使用不同,因此,需要注意!!

  1. 如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载。
#include "Priority_queue.h"

class Date
{
public:

	friend ostream& operator<<(ostream& _cout, const Date& d);

	Date(int year = 1900, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}

	bool operator <(const Date& d) const
	{
		return (_year < d._year)
			|| (_year == d._year && _month < d._month)
			|| (_year == d._year && _month == d._month && _day < d._day);
	}

	bool operator >(const Date& d) const 
	{
		return (_year > d._year)
			|| (_year == d._year && _month > d._month)
			|| (_year == d._year && _month == d._month && _day > d._day);
	}

	bool operator==(const Date& d)
	{
		return (_year == d._year 
			&& _month == d._month 
			&& _day == d._day);
	}

	bool operator!=(const Date& d)
	{
		return (_year != d._year)
			|| (_year == d._year && _month != d._month)
			|| (_year == d._year && _month == d._month && _day != d._day);
	}

private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day;
	return _cout;
}

struct PDateless //struct默认为public,comfunc()才能调用,class默认为private
{
	bool operator()(Date* p1, Date* p2)
	{
		return *p1 < *p2;
	}
};

void TestPriorityQueue()
{
	//大堆,需要用户在自定义类型中提供<重载
	own::priority_queue<Date*, vector<Date*>, PDateless> q1;
	q1.push(new Date(2024, 9, 13));
	q1.push(new Date(2024, 9, 14));
	q1.push(new Date(2024, 9, 15));

	while (!q1.empty())
	{
		cout << *q1.top() << " ";
		q1.pop();
	}
	cout << endl;

}

int main()
{
	TestPriorityQueue();

	return 0;
}

在这里插入图片描述

  1. 如 在OJ中的使用
    数组中的第K个最大元素:https://leetcode.cn/problems/kth-largest-element-in-an-array/description/
class Solution {
public:
	int findKthLargest(vector<int>& nums, int k) {
		// 将数组中的元素先放入优先级队列中
		priority_queue<int> p(nums.begin(), nums.end());

		// 将优先级队列中前k-1个元素删除掉
		for (int i = 0; i < k - 1; ++i)
		{
			p.pop();
		}

		return p.top();
	}
};

🌠仿函数的使用

仿函数/函数对象:重载了operator()的类,类的对象可以像函数一样使用operator()特点,参数个数和返回值根据需求确定,不固定,很灵活

// 定义一个仿函数类
class Add {
public:
	// 重载 operator(),接受两个参数并返回它们的和
	int operator()(int a, int b) {
		return a + b;
	}
};

int main() {
	// 创建仿函数对象
	Add add;

	// 使用仿函数
	int result = add(3, 4); // 调用 operator()
	std::cout << "3 + 4 = " << result << std::endl;

	return 0;
}

灵活使用:

class Func
{
public:

	void operator()(int n)
	{
		while (n--)
		{
			cout << "Func调用" << endl;
		}
		cout << endl;
	}
};
int main()
{

	//仿函数
	Func f1;
	f1(10);

	f1.operator()(10);


	return 0;
}

在这里插入图片描述

在这里插入图片描述

🌠C语言有趣的模仿push_back

void PushBack(int x)
{
	printf("void PushBack(int x)\n");
}

// C
struct Vector
{
	void(*push_back)(int);

	int* _a;
	int _size;
	int _capacity;
};

void Init(struct Vector* pv)
{
	pv->push_back = PushBack;
	//...
}

int main()
{
	Vector v;
	Init(&v);

	v.push_back(1);
	v.push_back(2);

	return 0;
}

在这里插入图片描述

🌠priority_queue的模拟实现

通过对priority_queue的底层结构就是堆,因此此处只需对对进行通用的封装即可。

  1. 基本框架
#pragma once
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

namespace own
{
	template<class T>
	struct myless
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T>
	struct mygreater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

	template <class T,class Container = vector<T>,class Compare = myless<T>>
	class priority_queue
	{
	public:
		//强制编译器生成
		priority_queue() = default;

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

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

		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}
  1. 使用迭代器添加元素数据进数组:
    当数据都进vector容器,我们随带建堆:
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		_con.push_back(*first);
		++first;
	}

	//从顶开始建堆
	for (size_t i = 0 ;i < _con.size();++i)
	{
		adjustup(i);
	}
}
  1. 建堆两种方式:向上建堆:向下建堆:
    在这里插入图片描述
//第一种
void adjustup(size_t child)
{
	Compare comfunc;
	while (child > 0)
	{
		size_t parent = (child - 1) / 2;
		if (comfunc(_con[parent], _con[child]))
		{
			swap(_con[parent], _con[child]);
			child = parent;
			parent = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//第二种
void adjustup(int child)
{
	Compare comfunc;

	while (child > 0)
	{
		size_t parent = (child - 1) / 2;
		if (comfunc(_con[parent], _con[child]))
		{
			swap(_con[child], _con[parent]);

			child = parent;

			//加不加这个parent都可以,因为上面可以再次获取,加了可以方便理解
			//parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
//}

//第三种
 //也可以是这样的写法
void adjustup(int child)
{
	Compare comfunc;
	size_t parent = (child - 1) / 2;
	//                      
	// 注意:这里的parent 和child的顺序要和adjustdown的if (comfunc(_con[parent] , _con[child]))比较顺序一致
	while (comfunc(_con[parent] , _con[child])) {
		swap(_con[child], _con[parent]);
		child = parent;
		parent = (child - 1) / 2;
	}
}
  1. 向下调整建堆:
void adjustdown(int parent)
{
	Compare comfunc;
	size_t child = 2 * parent + 1;

	while (child < _con.size())
	{
		if (child + 1 < _con.size() && comfunc(_con[child] , _con[child + 1]))
		{
			++child;
		}

		if (comfunc(_con[parent] , _con[child]))//注意:这里的parent 和child的顺序要和adjustupwhile (comfunc(_con[parent] , _con[child]))顺序一致
		{
			swap(_con[parent], _con[child]);

			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}
  1. 两个操作pushpop
    在这里插入图片描述
void push(const T& x)
{
	_con.push_back(x);
	adjustup(_con.size() - 1);
}

void pop()
{
	std::swap(_con[0], _con[_con.size()-1]);
	_con.pop_back();

	adjustdown(0);
}

在这里插入图片描述

priority_queue的源代码:

#pragma once
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

namespace own
{
	template<class T>
	struct myless
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T>
	struct mygreater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

	template <class T,class Container = vector<T>,class Compare = myless<T>>
	class priority_queue
	{
	public:
		//强制编译器生成
		priority_queue() = default;

		//
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				_con.push_back(*first);
				++first;
			}

			//从顶开始建堆
			for (size_t i = 0 ;i < _con.size();++i)
			{
				adjustup(i);
			}
		}


		//void adjustup(size_t child)
		//{
		//	Compare comfunc;
		//	while (child > 0)
		//	{
		//		size_t parent = (child - 1) / 2;
		//		if (comfunc(_con[parent], _con[child]))
		//		{
		//			swap(_con[parent], _con[child]);
		//			child = parent;
		//			parent = child * 2 + 1;
		//		}
		//		else
		//		{
		//			break;
		//		}
		//	}
		//}

		//void adjustup(int child)
		//{
		//	Compare comfunc;

		//	while (child > 0)
		//	{
		//		size_t parent = (child - 1) / 2;
		//		if (comfunc(_con[parent], _con[child]))
		//		{
		//			swap(_con[child], _con[parent]);

		//			child = parent;

		//			//加不加这个parent都可以,因为上面可以再次获取,加了可以方便理解
		//			//parent = (child - 1) / 2;
		//		}
		//		else
		//		{
		//			break;
		//		}
		//	}
		//}

		//i 为child
		 //也可以是这样的写法
		void adjustup(int child)
		{
			Compare comfunc;
			size_t parent = (child - 1) / 2;
			//                      
			// 注意:这里的parent 和child的顺序要和adjustdown的if (comfunc(_con[parent] , _con[child]))比较顺序一致
			while (comfunc(_con[parent] , _con[child])) {
				swap(_con[child], _con[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
		}
		
		//i为parent
		void adjustdown(int parent)
		{
			Compare comfunc;
			size_t child = 2 * parent + 1;

			while (child < _con.size())
			{
				if (child + 1 < _con.size() && comfunc(_con[child] , _con[child + 1]))
				{
					++child;
				}

				if (comfunc(_con[parent] , _con[child]))//注意:这里的parent 和child的顺序要和adjustupwhile (comfunc(_con[parent] , _con[child]))顺序一致
				{
					swap(_con[parent], _con[child]);

					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}




		void push(const T& x)
		{
			_con.push_back(x);
			adjustup(_con.size() - 1);
		}

		void pop()
		{
			std::swap(_con[0], _con[_con.size()-1]);
			_con.pop_back();

			adjustdown(0);
		}

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

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

		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

🚩总结

请添加图片描述

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

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

相关文章

小型企业如何利用人工智能的生产力

尽管生产力低下是一个长期存在的问题&#xff0c;但最近严峻的经济逆风加剧了这一问题&#xff0c;企业清算数量同比增长了 19&#xff05;。 Xero 的报告《小企业生产力&#xff1a;趋势、影响和战略》反映了这些宏观经济变化&#xff0c;显示 2023 年新西兰小企业生产力与 …

水平仪激光模组热了就不亮了怎么维修?

在建筑施工、装修设计或是精密测量等领域&#xff0c;水平仪作为不可或缺的工具&#xff0c;其准确性和稳定性直接关乎到工作的质量与效率。然而&#xff0c;许多用户在使用过程中会遇到这样一个问题&#xff1a;水平仪的激光模组在长时间使用或环境温度升高后&#xff0c;突然…

模拟实现通用型排序

本期介绍&#x1f356; 主要介绍&#xff1a;什么是泛型排序&#xff0c;即&#xff1a;无类型排序&#xff0c;以及库函数qsort()的使用&#xff0c;以及如何自己模拟实现一个泛型的冒泡排序。 文章目录 1. 什么是通用型排序2. 库函数qsort()2.1 定义2.2 使用 3. 模拟实现通用…

828华为云征文|部署多媒体流媒体平台 Plex

828华为云征文&#xff5c;部署多媒体流媒体平台 Plex 一、Flexus云服务器X实例介绍1.1 云服务器介绍1.2 性能模式1.3 计费模式 二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 Plex3.1 Plex 介绍3.2 Docker 环境搭建3.3 Plex 部署3.4 Plex 使…

Apple M3编译OpenSSL安卓平台SO库

1.下载OpenSSL源码: https://github.com/openssl/openssl.git 2.配置NDK环境变量:vim ~/.zprofile 添加ANDROID_NDK_ROOT环境变量,iosdev改为你自己的用户名 export ANDROID_NDK_ROOT=/Users/iosdev/Library/Android/sdk/ndk/23.1.7779620 添加NDK下可执行文件路径到PATH环…

Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)

导航&#xff1a; 【Java笔记踩坑汇总】Java基础JavaWebSSMSpringBootSpringCloud瑞吉外卖/谷粒商城/学成在线设计模式面试题汇总性能调优/架构设计源码解析 推荐视频&#xff1a; 黑马程序员全套Java教程_哔哩哔哩 尚硅谷Java入门视频教程_哔哩哔哩 推荐书籍&#xff1a; 《Ja…

ubuntu2204安装kvm

ubuntu2204安装kvm 前言一、检测硬件是否支持二、安装软件三、创建/管理虚拟机1、创建存储池2、qemu创建镜像3、xml文件运行虚拟机1、范文2、xml文件创建虚机3、创建虚机 4、克隆虚机5、创建快照6、脚本创建VNC连接 四、创建集群1、安装glusterfs2、加入集群删除节点 3、 创建卷…

EasyExcel 动态表头+表头合并

EasyExcel 动态表头表头合并 ​ 最终呈现效果&#xff1a; ​ 以前对EasyExcel的使用都是一个实体类字段对应一列&#xff0c;通过以下来一一对应即可。 ExcelProperty(index 0,value "姓名" ) private String xm;​ 所以此中出现的两个问题&#xff1a; 表头合并…

【LeetCode每日一题】——LCR 168.丑数

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目注意】六【题目示例】七【题目提示】八【解题思路】九【时间频度】十【代码实现】十一【提交结果】 一【题目类别】 优先队列 二【题目难度】 中等 三【题目编号】 LCR 168.丑数 四【题目描述…

多输入多输出 | Matlab实现SO-BP蛇群算法优化BP神经网络多输入多输出预测

多输入多输出 | Matlab实现SO-BP蛇群算法优化BP神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现SO-BP蛇群算法优化BP神经网络多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 多输入多输出 | Matlab实现SO-BP蛇群算法优化BP神经网络多输…

1688竞品分析这样做,超越电商同行,流量想不爆都难!

竞品分析最大的意义就是知己知彼&#xff01;清楚自己所在的位置&#xff0c;取长补短&#xff0c;确定下一阶段打法和方向。那么该怎么做竞品分析&#xff1f; 我们利用店雷达1688工具进行实操讲解&#xff0c;分别从竞品目标、价格机制、流量结构&#xff0c;3个方面教你迅速…

uniapp 做一个查看图片的组件,图片可缩放移动

因为是手机端&#xff0c;所以需要触摸可移动&#xff0c;双指放大缩小。 首先在components里建个组件 查看图片使用 uni-popup 弹窗 要注意 transform的translate和scale属性在同一标签上不会一起生效 移动就根据触摸效果进行偏移图片 缩放就根据双指距离的变大变小进行缩…

前端练习小项目 —— 养一只电子蜘蛛

前言&#xff1a;在学习完JavaScript之后&#xff0c;我们就可以使用JavaScript来实现一下好玩的效果了&#xff0c;本篇文章讲解的是如何纯使用JavaScript来实现一个网页中的电子蜘蛛。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-C…

2.3.1 协程设计原理与汇编实现coroutine

LINUX 精通 7 day23 20240908 晚19&#xff1a;25 - 21:30 课程链接地址 2.3.1 协程设计原理与汇编实现coroutine 目的 协程不是某种语言特有的&#xff0c;lua&#xff0c;go都有 ntyco 是king老师自己写的 原语操作&#xff1a;“原语操作”通常指的是在编程或计算机科学中…

Android 12系统源码_窗口管理(八)WindowConfiguration的作用

前言 在Android系统中WindowConfiguration这个类用于管理与窗口相关的设置&#xff0c;该类存储了当前窗口的显示区域、屏幕的旋转方向、窗口模式等参数&#xff0c;应用程序通过该类提供的信息可以更好的适配不同的屏幕布局和窗口环境&#xff0c;以提高用户体验。 一、类定…

性能测试的复习2-jmeter的搭建、使用、参数化

通过网盘分享的文件&#xff1a;性能测试共享文件 链接: https://pan.baidu.com/s/1A4Nc8C5Xp6qxQ5QFtecK8g?pwds73c 提取码: s73c 1、性能测试工具 2、jmeter环境搭建 3、jmeter的基本使用 4、jmeter的参数化

strncpy函数的使用和模拟实现

目录 1.头文件 2.strncpy函数功能 2.1情况二&#xff1a; 3.strncpy函数&#xff08;模拟实现&#xff09; 方源一把抓住VS2022&#xff0c;催动春秋产的气息&#xff0c;顷刻炼化&#xff01; 1.头文件 strncpy函数的使用需要包括头文件<string.h> #include<string…

Windows系统好用软件推荐

uTools uTools官网&#xff1a;https://u.tools/download/ 功能介绍&#xff1a; 内置许多有用的插件、快速打开应用、复制图片保存等

4457E/4457F/4457G/4457K数字示波器

KEYSIGHT是德 4457E/4457F/4457G/4457K数字示波器 4457系列数字示波器共4个产品型号&#xff0c;产品带宽从1GHz到4GHz&#xff0c;采样率10GSa/s、20GSa/s&#xff0c;垂直分辨率8bit&#xff0c;存储深度2Gpts&#xff0c;最快波形捕获率120万个波形/秒&#xff0c;独创的An…

LIN帧显隐性电平和字节传输顺序理解

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…