【C++】priority_queue (优先队列)

priority_queue 的介绍

1.优先队列的底层是用堆实现的,而且默认大堆。
2.优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的一个。
3.优先队列可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
4.优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为底层容器类,queue 提供一组特定的成员函数来访问其元素,元素从特定元素的尾部弹出,其成为优先队列的顶部。
5.底层容器可以是任意标准类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问,迭代器访问,并支持以下操作:

*empty():检验容器是否为空
*size():返回容器中有效元素个数
*front():返回容器中第一个元素的引用
*push_back():在容器尾部插入元素
*pop_back():删除容器尾部的元素

6.标准容器类vector和deque都满足这些条件,但默认会使用vector容器。
7.需要支持随机访问迭代器,以便在内部始终保持堆结构。容器适配器通过在需要时自动调用算法函数来完成所需操作。

priority_queue 的使用
1.默认情况下,创建大堆,底层按小于号比较

此时第三个模板参数默认less

#include <queue>
#include <vector>
#include <functional>    //greater算法的头文件
#include<iostream>
using namespace std;
int main()
{
	priority_queue<int> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	q1.push(4);
	q1.push(5);
	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl;
	system("pause");
	return 0;
}

结果如下:
在这里插入图片描述

2.如果要创建小堆,需要用到仿函数修饰优先级

此时要加头文件< functional> 并按下面的模板

template <class T, class Container = vector,class Compare = less > 

将第三个模板参数换成gerater 比较方式:此时代码实现及结果

int main()
{
	priority_queue<int,vector<int>,greater<int>> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	q1.push(4);
	q1.push(5);
	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl;
	system("pause");
	return 0;
}

在这里插入图片描述

3.如果在priority_queue 中放自定义类型的数据,用户需要在自定义类型中提供> 或< 的重载。(只要有> <的重载即可)

这里,我以日期类为例,供大家参考。

class Date
{
public:
	Date(int year = 1999, 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)    
	{
		_cout << d._year << "-" << d._month << "-" << d._day;
		return _cout;
	}
private:
	int _year;
	int _month;
	int _day;
};
void TestPQ()
{
	priority_queue<Date> q2;   //此时默认大堆,只要在自定义类型中提供< 的重载
	q2.push(Date(2018, 12, 11));
	q2.push(Date(2014, 11, 01));
	q2.push(Date(2014, 12, 14));
	q2.push(Date(2015, 03, 21));
	while (!q2.empty())
	{
		cout << q2.top() << " ";
		q2.pop();
	}
}

在这里插入图片描述
如果要建小堆,只要在自定义类型中提供> 的重载

priority_queue<Date, vector<Date>, greater<Date>> q2;

在这里插入图片描述

4.有些情况下,用户可能要自己提供比较规则

下面我写了一个商品按价格排序的实例,供大家理解。

class Goods
{
public:
	bool operator<(const Goods r) const      //重载小于号
	{
		return _price < r._price;
	}
public:
	int _price;
	int _sales_volume;
	int _evaluation;
	int _comprehensive;
};

struct GoodsPriceLess       //大堆的比较规则
{
	bool operator()(const Goods& l, const Goods& r)
	{
		return l._price < r._price;
	}
};

struct GoodsPriceGreater       //小堆的比较规则
{
	bool operator()(const Goods& l, const Goods& r)
	{
		return l._price > r._price;
	}
};
void TestPQ3()
{
	priority_queue<Goods, vector<Goods>, GoodsPriceLess> goodspq;
	goodspq.push(Goods{ 1, 8, 8, 4 });
	goodspq.push(Goods{ 9, 8, 7, 6 });
        // 只按价格比
	Goods top = goodspq.top();
	cout << top._price << "  ";
	cout << top._sales_volume << "  ";
	cout << top._evaluation << "  ";
	cout << top._comprehensive << endl;
}

在这里插入图片描述

模拟实现 priority_queue 的功能

因为优先队列的底层是堆,所以在进行push和pop时,需要进行调堆。
附以下代码供大家参考。

template<class T, class Container = vector<T>, class Compare = less<T>>
class PriorityQueue
{
public:
	void Adjustup(int child)        //向上调堆
	{
		int parent = (child - 1) >> 1;
		while (child > 0)
		{
			Compare com;
			if (com(_con[parent], _con[child]))
			{
				swap(_con[parent], _con[child]);
				child = parent;
				parent = (child - 1) >> 1;
			}
			else
			{
				break;
			}
		}
	}

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

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

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

	void Pop()
	{
		swap(_con[0], _con[_con.size() - 1]);
		_con.pop_back();
		AdjustDown(0);
	}

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

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

	bool Empty()
	{
		return _con.empty();
	}
private:
	Container _con;
};
void TestPQ4()
{
	PriorityQueue<int> q4;
	q4.Push(4);
	q4.Push(3);
	q4.Push(8);
	q4.Push(1);
	cout << q4.Top() << endl;
}

在这里插入图片描述
我暂时就写到这里啦,大家有其他想法和建议欢迎留言讨论哟~

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值