C++ priority_queue 优先级队列

一.什么是priority_queue(优先级队列)

优先级队列是一种容器适配器,数据的存储是采用堆的形式实现的,保证第一个元素是优先级队列的最大值或最小值。(默认建大堆)

默认用vector作为底层数据的存储容器。

二.priority_queue的三个类模板参数

1.class T

T是优先级队列中存储元素的类型

2.class Container = vector<T>

Container是优先队列底层使用的存储结构(默认用vector)

3.class Compare = less<typename Container::value_type>

Compare是定义元素比较的方式。(默认less建大堆)

为什么根据Compare可以对元素进行比较呢?

首先我们要了解什么是仿函数。

仿函数

仿函数实际上是一个类的对象,通过operator() 运算符重载来模拟函数调用的过程。

可以利用模板对不同元素进行比较。

因为要建小堆或者大堆,比较方式会不同。就需要Compare接收不同的类来改变比较方式。

template<class T>
class less
{
public:
	bool operator()(T a, T b)
	{
		return a < b;
	}
};
template<class T>
class greater
{
public:
	bool operator()(T a, T b)
	{
		return a > b;
	}
};
	template<class T, class Container = vector<T>,class Compare=less<T>>
	class PriorityQueue
	{
	public:
		PriorityQueue() = default;//强制生成默认构造
		template <class InputIterator>
		PriorityQueue(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				c.push_back(*first);
				first++;
			}
			size_t parent = (c.size() - 1 - 1) / 2;
			while (parent > 0)
			{
				size_t child = parent * 2 + 1;
				if (child + 1 < c.size() && comp(c[child], c[child + 1]))
				{
					child++;
				}
				if (c[parent] < c[child]) swap(c[parent], c[child]);
				parent--;
			}
		}
	private:
		Container c;
		Compare comp;
	};
}

建大堆就传入less类,小堆就传入greater类

自定义类型比较

如果优先级队列中存入的是自定义类型,那应该怎么进行比较呢?
这就需要我们在自定义类型的类中重载大于> 小于< 。这样在less greater类的函数中就可以对><进行重载,实现大小的比较。

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;
}

但如果我要存入Date对象的地址呢?
less greater类中函数直接比较的就是地址的大小。

那我们可以新建一个类,先对地址解引用,在利用函数重载进行比较。

struct PDateLess
{
	bool operator()(Date* p1, Date* p2)
	{
		return *p1 < *p2;
	}
};
struct PDateGreater
{
	bool operator()(Date* p1, Date* p2)
	{
		return *p1 > *p2;
	}
};
void TestPriorityQueue()
{
	// 大堆,需要用户在自定义类型中提供<的重载
	wws::PriorityQueue<Date*, vector<Date*>, PDateLess> q1;
	q1.push(new Date(2024, 6, 1));
	q1.push(new Date(2024, 6, 2));
	q1.push(new Date(2024, 6, 3));

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

三.priority_queue模拟实现

#pragma once
#include<iostream>
using namespace std;
#include<vector>
namespace wws
{

	template<class T>
	class less
	{
	public:
		bool operator()(T a, T b)
		{
			return a < b;
		}
	};
	template<class T>
	class greater
	{
	public:
		bool operator()(T a, T b)
		{
			return a > b;
		}
	};
	template<class T, class Container = vector<T>,class Compare=less<T>>
	class PriorityQueue
	{
	public:
		PriorityQueue() = default;//强制生成默认构造

		template <class InputIterator>
		PriorityQueue(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				c.push_back(*first);
				first++;
			}
			size_t parent = (c.size() - 1 - 1) / 2;
			while (parent > 0)
			{
				size_t child = parent * 2 + 1;
				if (child + 1 < c.size() && comp(c[child], c[child + 1]))
				{
					child++;
				}
				if (c[parent] < c[child]) swap(c[parent], c[child]);
				parent--;
			}
		}
		void push(const T& x)
		{
			c.push_back(x);
			size_t child = c.size() - 1;
			while (child > 0)
			{
				size_t parent = (child - 1) / 2;
				if (comp(c[parent] , c[child]))
				{
					swap(c[parent], c[child]);
					child = parent;
				}
				else break;
			}
		}
		void pop()
 		{
			swap(c[0], c[(c.size() - 1)]);
			c.pop_back();
			size_t parent = 0, child = parent * 2 + 1;
			while (child<c.size())
			{
				if (child + 1 < c.size() && comp(c[child], c[child+1]))
				{
					child++;
				}
				if (comp(c[parent], c[child]))
				{
					swap(c[parent], c[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else break;
			}
		}
		bool empty() const
		{
			return c.empty();
		}

		size_t size() const
		{
			return c.size();
		}

		const T& top() const
		{
			return c.front();
		}
	private:
		Container c;
		Compare comp;
	};
}

  • 17
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值