当前位置: 首页 > article >正文

c++中priority_queue的应用及模拟实现

1.介绍

priority_queue 是一种数据结构,它允许你以特定的顺序存储和访问元素。在 C++ 标准模板库(STL)中,priority_queue 是一个基于容器适配器的类模板,它默认使用 std::vector 作为底层容器,并且默认使用最大堆来存储元素。priority_queue 中的元素按照优先级顺序排列。默认情况下,优先级最高的元素(即值最大的元素)位于队列的顶部。访问时,只能访问优先级最高的元素(即队列顶部的元素),不能直接访问其他元素。

2.代码体验

测试代码:


#include<vector>
#include<queue>	
#include<iostream>
using namespace std;
int main()
{
	priority_queue<int> pq;
	pq.push(20);
	pq.push(5);
	pq.push(60);
	pq.push(80);
	pq.push(3);
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;
	return 0;
}

运行结果如下:

结果证明,元素确实是按大根堆的形式存储的!

3.自定义比较函数

priority_queue除了直接用于排序元素之外,还能用于自定义比较函数,来改变元素的优先级顺序例如,如果你想让优先队列按照元素的某个属性排序,可以定义一个比较函数

代码示例:

class date
{
	friend ostream& operator<<(ostream& _cout, const date& d);
public:
	date(int year=2025,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);
	}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout, const date& d)
{
	_cout << d._year << " " << d._month << " " << d._day;
	return _cout;
}

int main()
{
	priority_queue<date, vector<date>, greater<date>> q1;
	//解释一下这里为什么要写三个参数,而之前的应用为什么写一个参数就可:
	//这是由于priority_queue的模板就是这样给的,(详见下方图片),由于我们要进行
	//日期的某种排序,需要把第三个参数写上,而c++规定,你要写第三个参数 前面的第二个就必须写
	//所以我们第二个参数要写上!
	q1.push(date(2025, 1, 27));
	q1.push(date(2024, 10, 6));
	q1.push(date(2025, 5, 8));
	while (!q1.empty())
	{
		cout<< q1.top()<<endl;
		q1.pop();
	}
	return 0;
}

 

运行结果如下:

那个比较函数我们也可以自己来写,也支持的!

class date
{
	friend ostream& operator<<(ostream& _cout, const date& d);
public:
	date(int year=2025,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);
	}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout, const date& d)
{
	_cout << d._year << " " << d._month << " " << d._day;
	return _cout;
}
int main()
{
	priority_queue<date, vector<date>> q2;
	q2.push( date(2025, 1, 27));
	q2.push( date(2024, 10, 6));
	q2.push( date(2025, 5, 8));
	while (!q2.empty())
	{
		cout << q2.top() << endl;
		q2.pop();
	}
	return 0;
}

结果如下:

 

我们也可以写一个比较函数来进行比较

比较函数参数:

struct lessdate                          //自定义一个比较函数
{
	bool operator()(date* p1, date* p2)
	{
		return *p1 < *p2;
	}
};

main函数也要变一下:

​
int main()
{
	priority_queue<date*, vector<date*>, lessdate> q2;
	q2.push(new date(2025, 1, 27));
	q2.push(new date(2024, 10, 6));
	q2.push(new date(2025, 5, 8));
	while (!q2.empty())
	{
		cout << *q2.top() << endl;
		q2.pop();
	}
	return 0;
}

​

解释一下这里为什么要new一下,我们的q2是指针, 存储的是指针而不是对象,通过创建一个对象,并将其地址推入q2中,所以要new一下,此外,我们还要加一个比较函数,如果不加直接比的话,就是按照地址的大小来确定输出了,而与输入内容的大小无关了!

注:若比较函数参数不是指针,而是date p1,date p2,那main函数就不需要new date了! 

4.模拟实现priority_queue

 由于其默认使用最大堆来存储元素,因此我们在模拟实现时2,务必要涉及到堆的相关算法,如向上调整算法以及向下调整算法,如有遗忘可以找我之前的博客看一下,在本篇我也会略作讲解

1)基本框架:

#include<vector>
namespace rens
{
	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 ,class compare>
	class priority_queue
	{
	public:
	private:
		container _con;
	};
}

插入数据:和二叉树,堆一样,先将插入的数据放在最下面的叶结点,在逐步向上调整,以达到最大堆的结构 

删除数据:不要直接将最上面的删去,这样会造成这棵树“辈分混乱、群龙无首”,应先将最上面的数与最后一个数据交换,在向下调整,调整完毕后,删去最后一个数据

整体代码实现:

#include<vector>
#include <iostream>
namespace rens
{
	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=std::vector<T> ,class compare=less<T>>
	class priority_queue
	{
	public:
		void adjust_up(size_t child)
		{
			compare com;
			size_t parent = (child - 1) / 2;
			while (child > 0)
			{
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[child], _con[parent]);          //我们要排大堆,大的往上走
					child = parent;
					parent = (child - 1) / 2;
				}
				else 
				{
					break;
				}
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}
		void adjust_down(size_t parent)
		{
			compare com;
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				//先找最小孩子
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
				{
					++child;
				}
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}
		T&  top()
		{
			return _con[0];
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		container _con;
	};
}

代码测试:

#include"priority_queue.h"
#include<iostream>
using namespace std;
//小的优先级高

int main()
{
	cout << "升序" << endl;
	rens::priority_queue<int, std::vector<int>, rens::greater<int>> pq;
	pq.push(2);
	pq.push(5);
	pq.push(4);
	pq.push(1);
	pq.push(50);
	while (!pq.empty())
	{
		std::cout << pq.top()<<" ";
		pq.pop();
	}
	cout << endl << "降序"<<endl;
	//默认是最大的,因为我们默认参数给的是Less
	rens::priority_queue<int, std::vector<int>> pq1;
	pq1.push(2);
	pq1.push(5);
	pq1.push(4);
	pq1.push(120);
	pq1.push(1);
	while (!pq1.empty())
	{
		cout << pq1.top()<<" ";
		pq1.pop();
	}
	cout << endl;

	return 0;
}

5.仿函数

 在 C++ 中,仿函数(Functor)是一种重载了函数调用操作符 operator() 的类或结构体。仿函数可以像函数一样被调用,但它们实际上是对象。仿函数通常用于定义特定行为,它们可以被传递给算法,如 std::sortstd::for_each,以自定义这些算法的行为。

#include<vector>
#include <iostream>
namespace rens
{
	template<class T>
	class less
	{
	public:
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};
}
bool lessfunc(int x, int y)
{
	return x < y;
}
int main()
{
	bool (*ptr)(int, int) = lessfunc;
	rens::less<int> lessfunc;
	cout << lessfunc(1, 2) << endl;
}


http://www.kler.cn/a/533405.html

相关文章:

  • C#面试常考随笔13: 泛型的主要约束和次要约束是什么?
  • blender 相机参数
  • STM32 DMA+AD多通道
  • Nacos 的介绍和使用
  • 硬件产品经理:需求引力模型(DGM)
  • 手写MVVM框架-实现简单的数据代理
  • Git--使用教程
  • 19爬虫:使用playwright登录超级鹰
  • 2025春招,高级程序员回答数据库问题
  • Kubernetes | Rocky Linux 8.9 安装部署 kubernetes集群
  • 4.回归与聚类算法 4.1线性回归
  • 学前端框架之前,你需要先理解 MVC
  • 【llm对话系统】大模型 Llama 如何进行量化和推理
  • FPV光纤无人机军事战场技术详解
  • 图像分类与目标检测算法
  • 基于全志H616的智能家居
  • R语言速通
  • PyQt6/PySide6 的 QDialog 类
  • Spring Security(maven项目) 3.0.3.1版本 - 动态JDBC认证
  • https是如何保证安全的,又是如何保证不被中间人攻击的?
  • 防火墙的安全策略
  • VMware ThinApp 和VMware Workstation
  • MyBatis 调优指南:释放持久层性能潜力
  • 论计算机网络技术专业如何?创新
  • Aosp 15 编译遇到问题排查
  • Docker数据卷管理及优化