《priority_queue的模拟实现》

news2025/1/12 20:00:42

本文主要介绍

文章目录

  • 一、仿函数
    • 1.1 仿函数的定义
    • 1.2 普通仿函数
    • 1.3 需要自己实现仿函数
  • 二、priority_queue的模拟实现



一、仿函数

1.1 仿函数的定义

所谓的仿函数(functor),是通过重载()运算符模拟函数形为的类。
因此,这里需要明确两点:

  1. 仿函数不是函数,它是个类;
  2. 仿函数重载了()运算符,使得它的对你可以像函数那样子调用(代码的形式好像是在调用函数)。(C语言中就是函数指针)

1.2 普通仿函数

struct Less
{
	bool operator()(int x,int y)
	{
		return x < y;
	}
};
struct Greater
{
	bool operator()(int x,int y)
	{
		return x > y;
	}
};
int main()
{
	// Less就叫仿函数类型  less就叫函数对象
	Less less;
	cout << less(1, 2) << endl;

	Greater gt;
	cout << gt(1, 2) << endl;
	cout << gt.operator()(1,2) << endl;//两者等价
	return 0;
}

为了适应更多的类型可以加入模板

//仿函数
template<class T>
struct Less
{
	bool operator()(const T& x,const T& y)const
	{
		return x < y;
	}
};

template<class T>
struct Greater
{
	bool operator()(const T& x, const T& y)const
	{
		return x > y;
	}
};
int main()
{
	// Less就叫仿函数类型  less就叫函数对象
	Less<int> less;
	cout << less(1, 2) << endl;

	Greater<int> gt;
	cout << gt(1, 2) << endl;
	cout << gt.operator()(1,2) << endl;
	cout << Greater<double>()(3.14, 8.9) << endl;// 可以用匿名对象
	return 0;
}

1.3 需要自己实现仿函数

如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供<或者>的重载

class Date
{
public:
	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);
	}

	//类内声明,类外定义
	friend ostream& operator<<(ostream& _cout, const Date& d);
	
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day;
	return _cout;
}
void test_priority_queue2()
{
	//priority_queue<Date> pq;
	priority_queue<Date,vector<Date>,greater<Date>> pq;

	pq.push(Date(2022, 1, 1));
	pq.push(Date(2022, 1, 2));
	pq.push(Date(2022, 1, 3));
	pq.push(Date(2022, 1, 4));
	
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;
}

此处我们想存一个日期类进行比较,我们如果使用默认的less或者greater,他就会去比较两个日期类对象,但是我们想要比较的是具体的日期大小。
在这里插入图片描述
所以我们自定义的类型中要提供< 或者 >的重载,在进行比较时,会去调用用户提供的<或者>的重载函数

还有什么特殊情况下,需要我们自己实现仿函数吗?
如下例子:我们在priority_queue中存放自定义类型的指针,我们需要比较的是指针就引用以后的具体日期。

void test_priority_queue2()
{
	priority_queue<Date*> pq;
	//priority_queue<Date,vector<Date>,greater<Date>> pq;

	pq.push(new Date(2022, 1, 9));
	pq.push(new Date(2022, 1, 2));
	pq.push(new Date(2022, 1, 3));
	pq.push(new Date(2022, 1, 4));
	
	while (!pq.empty())
	{
		cout << *pq.top() << " ";
		pq.pop();
	}
	cout << endl;
}

此时的less或者greater直接取的Date里面的地址进行比较,由于new地址是堆上的空闲随机地址,故这是不可行的,需要自己实现仿函数

class Date
{
	friend class MyLess;//类外拿不到成员变量,搞成友元的
public:
	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);
	}*/

	//类内声明,类外定义
	friend ostream& operator<<(ostream& _cout, const Date& d);
	
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day;
	return _cout;
}
struct MyLess
{
	bool operator()(const Date* d1, const Date* d2)const
	{
		return (d1->_year < d2->_year) ||
			(d1->_year == d2->_year && d1->_month < d2->_month) ||
			(d1->_year == d2->_year && d1->_month == d2->_month && d1->_day < d2->_day);
	}
};
void test_priority_queue2()
{
	priority_queue<Date*,vector<Date*>,MyLess> pq;
	//priority_queue<Date,vector<Date>,greater<Date>> pq;

	pq.push(new Date(2022, 1, 9));
	pq.push(new Date(2022, 1, 2));
	pq.push(new Date(2022, 1, 3));
	pq.push(new Date(2022, 1, 4));
	
	while (!pq.empty())
	{
		cout << *pq.top() << " ";
		pq.pop();
	}
	cout << endl;
}

总结:
如果数据类型,不支持比较,或者比较的方式,不是你想要的那么可以自己实现仿函数,按照自己想要的方式去比较,控制比较逻辑

二、priority_queue的模拟实现

priority_queue底层是堆的结构,因此只需要对堆进行封装即可

#pragma once
#include <assert.h>

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

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

	template <class T, class Container = vector<T>, class Compare = Less<T>> //默认是大堆
	class priority_queue
	{
	public:
		priority_queue()
			:_con()
		{}

		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last) //相当于传迭代器区间构造vector,只对这个区间的内容建堆
		{
			//从最后一个孩子的开始调整建堆
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; --i)
			{
				AdjustDown(i);
			}
		}

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

		void pop()
		{
			assert(!empty());
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}

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

		int size() const
		{
			return _con.size();
		}
		
		bool empty() const
		{
			return _con.size() == 0;
		}
	private:
		
		void Adjustup(size_t child)
		{
			size_t parent = (child - 1) / 2;
			while (child > 0)
			{
				Compare com;
				//if (_con[parent] < _con[child])
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void AdjustDown(size_t parent)
		{
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				Compare com;
				//if (child + 1 < _con.size() && _con[child] < _con[child + 1])
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
				{
					child++;
				}

				//if (_con[parent] < _con[child])
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		Container _con;
	};

	void test1()
	{
		priority_queue<int,vector<int>,Greater<int>>  pq;
		pq.push(1);
		pq.push(2);
		pq.push(3);
		pq.push(4);
		pq.push(5);
		pq.push(6);

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

		//测试 迭代去区间构造
		int arr[] = { 1,6,5,8,2,7,6 };
		priority_queue<int>  pq2(arr, arr + sizeof(arr)/sizeof(arr[0]));
		while (!pq2.empty())
		{
			cout << pq2.top() << " ";
			pq2.pop();
		}
		cout << endl;
	}
}

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

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

相关文章

纯干货:数据库连接耗时慢原因排查

背景 最近公司的社区相关的服务需要优化&#xff0c;由于对业务不熟悉&#xff0c;只能借助监控从一些慢接口开始尝试探索慢的原因。由于社区相关的功能务是公司小程序流量入口&#xff0c;所以相应的服务访问量还是比较高的。针对这类高访问的项目&#xff0c;任何不留神的地…

中睿天下参编的《中国网信产业桔皮书-数据安全》正式发布

5月28日&#xff0c;2023中关村论坛中关村国际技术交易大会第七届中国网信产业前锋汇成功举办&#xff0c;本次会议以“全球数字经济发展与数据安全关键技术”为主题&#xff0c;会议由中国&#xff08;中关村&#xff09;网络安全与信息化产业联盟主办&#xff08;以下简称联盟…

芯片的XIP与BootRom启动方式

XIP&#xff1a;execute in place&#xff0c;就地执行&#xff0c;即芯片内执行&#xff0c;指应用程序可以直接在flash闪存中取指然后译码、执行&#xff0c;不必再把代码读到系统RAM中&#xff0c;flash内执行时指Nor flash不需要初始化&#xff0c;可以直接在flash内执行代…

Elsevier期刊中,撰写Author Statement

Author Statement或Authorship Contribution通常指作者声明&#xff0c;用于声明当前学术论文中每位作者的贡献。 大部分期刊都要求作者在首次投稿的时候就添加这部分内容&#xff0c;也有一些仅要求在发表之前提交。作者声明指导与模板有些学术期刊会专门提供具体的作者声明模…

Vue3 mixin 自定义指令 teleport

文章目录 Vue3 mixin & 自定义指令 & teleportmixin 混入简单使用 自定义指令简单使用全局注册参数 teleport 传送门简单使用 Vue3 mixin & 自定义指令 & teleport mixin 混入 mixins 选项接受一个 mixin 对象数组。这些 mixin 对象可以像普通的实例对象一样…

【企业化架构部署】Apache网页优化

文章目录 一、Apache网页优化概述1.优化内容2.网页压缩2.1gzip概述2.2作用2.3Apache的压缩模块概述mod_gzip模块与mod_deflate模块 3.配置网页压缩功能3.1启用网页压缩功能步骤3.2具体操作步骤 4.配置网页缓存功能4.1启用网页压缩功能步骤4.2具体操作步骤 二、Apache安全优化1.…

【JVM】.class类文件是如何被加载的?

一、类加载过程 .class文件最终加载到JVM并使用整体步骤及图示如下&#xff1a; 每个步骤所做的事情如下&#xff1a; 1、加载 &#xff08;1&#xff09;通过一个类的全限定名来获取该类文件的二进制字节流&#xff1b;&#xff08;读取class文件到内存中&#xff09; &am…

点击这里!解锁海量数据在openGauss Developer Day 2023的高光时刻

5月26日&#xff0c;openGauss Developer Day 2023在此起彼伏的掌声中圆满落幕。最前沿的核心产品、最深度的专业解读、最全面的落地案例......海量数据在此次盛会上时时高光&#xff0c;事事精彩&#xff0c;尤其是在专场分论坛上&#xff0c;数据库领域各路精英济济一堂&…

linuxOPS基础_linux文件检索及筛选

find命令 查找文件 主要功能&#xff1a;当我们查找一个文件时&#xff0c;必须使用的一个命令。 find 搜索路径 [选项]选项选项说明-name指定要搜索文件的名称&#xff0c;支持*星号通配符&#xff08;Shift 8&#xff09;-type代表搜索的文件类型&#xff0c;f代表普通文件…

使用开源代码和开源软件如何选择开源许可证

常用的开源许可证 世界上的开源许可证大约有近百种&#xff0c;如何使用开源代码和开源软件并正确理解、遵守这些开源许可证赋予的权利和义务是个比较繁琐的问题&#xff0c;我们对其中主要的六种许可证GPL、BSD、MIT、Mozilla、Apache和LGPL做个简单的梳理&#xff0c;对比一下…

什么是企业移动化管理 (EMM)

什么是EMM或企业移动化管理 企业移动化管理 &#xff08;EMM&#xff09; 是组织用来保护公司拥有和员工拥有的移动设备上的敏感公司数据的一组策略和做法。Mobile Device Manager Plus 是一个全面的 EMM 解决方案&#xff0c;允许 IT 团队和管理员跨多个平台管理设备&#xf…

推进产业发展健全服务体系,中国信通院数字员工评测工作正式启动

数字技术与应用正在快速重塑全新的经济发展格局&#xff0c;创新应用人工智能、大数据、云计算等新兴技术是企业实施数字化转型的重要策略之一。 “数字员工”是数字生产力与创造力体系的核心要素&#xff0c;自动化、智能化的执行模式将成为企业业务运营的新常态。随着数字员…

外包实在是太坑了,划水三年,感觉人都废了

先说一下自己的情况&#xff0c;专科生&#xff0c;19年通过校招进入杭州某个外包软件公司&#xff0c;干了接近3年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了3年的功…

革命性3D打印数据处理软件 CHITUBOX Pro 1.3.0 Crack

CHITUBOX PRO登场 革命性的3D打印数据处理软件&#xff0c;让你发挥3D打印的无限潜力 支持多种主流CAD文件格式 除了传统的stl和obj文件&#xff0c;CHITUBOX Pro还支持导入各种主流的CAD文件格式&#xff0c;包括3ds、3mf、3dm、stp、step、wrl、x3d、sat、sab、dae、dxf、fb…

5.2.5 IP数据报(三)IP数据报的分片与重组

5.2.5 IP数据报&#xff08;三&#xff09;IP数据报的分片与重组 前面我们在学习IP数据报的格式中&#xff0c;提及了数据报的分片&#xff0c;这里我们要弄明白几个问题 为什么要分片&#xff1f; 前面我们已经解释过&#xff0c;如图 因为在数据报传送的过程中如果总长度超出…

Sui教育资助计划:共同构建Web3教育的未来

Sui教育资助计划旨在通过与社区成员一起构建公开的教育资料&#xff0c;加速推广Web3&#xff0c;并支持Sui生态系统的发展。 内容类别 包括教程、指南、视频以及文本等形式的教育材料包括学习奖励和其他体验式的教育产品&#xff0c;将学习游戏化可帮助开发人员加快构建速度…

基于matlab使用差分波束成形技术形成线性差分麦克风阵列

一、前言 本示例展示了差分波束成形的基本概念&#xff0c;以及如何使用该技术形成线性差分麦克风阵列。 二、加法与差分麦克风阵列 麦克风阵列已部署在许多音频应用中。根据布局的不同&#xff0c;麦克风阵列可分为两大类&#xff1a;加法麦克风阵列和差分麦克风阵列。附加麦克…

机器视觉陶瓷检测设备稳定性怎么样?不稳定因素有哪些?

机器视觉陶瓷检测设备是一种利用现代计算机视觉技术对陶瓷产品进行快速、高效的缺陷检测的设备。相比传统的人工检测方法&#xff0c;机器视觉陶瓷检测设备具有检测速度快、精度高、可靠性强等优点&#xff0c;可以大大提高陶瓷生产线的生产效率和产品质量。但是&#xff0c;由…

学成在线(视频处理-需求分析:xxl-job)

需求分析 作业分片方案 任务添加成功后&#xff0c;对于要处理的任务&#xff0c;会添加到待处理任务表中&#xff0c;现在启动多个执行器实例去查询这些待处理任务&#xff0c;此时如何保证多个执行器不会重复执行任务&#xff1f;在上一小节的测试中&#xff0c;每个执行器…

VMware ESXi 8.0U1a Unlocker OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版)

VMware ESXi 8.0 Update 1a Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版) 发布 ESXi 8.0U1 集成驱动版&#xff0c;在个人电脑上运行企业级工作负载 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-8-u1-sysin/&#xff0c;查看最新版。原…