STL--priority_queue(介绍以及使用和模拟实现)

一、priority_queue的使用

template <class T, class Container = vector<T>,class Compare = less<typename Container::value_type> > 
class priority_queue;

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

有关堆结构,可以参考我的另外一篇博客有详细说明了对堆的分析,包括建堆,堆排序,堆向上、向下调整:图解二叉堆:堆排序

1.1、priority_queue的常用接口

函数声明接口说明
priority_queue()/priority_queue(first,last)构造一个空的优先级队列
empty()检测优先级队列是否为空
top()返回优先级队列中优先级堆高的元素,堆顶元素
push(x)在优先级队列中插入元素x
pop()删除优先级队列中堆顶的元素

1.2、默认情况下priority_queue是大堆

#include <vector>
#include <queue>		//priority_queue 的头文件
#include <functional> // greater算法的头文件

int main() {
	// 默认情况下,创建的是大堆,其底层按照小于号比较
	vector<int> v{ 3,2,7,6,0,4,1,9,8,5 };
	priority_queue<int> q1;
	for (auto& e : v)
		q1.push(e);
	cout << "默认less比较方式大根堆输出:" << endl;
	while (!q1.empty()) {
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl;

	// 如果要创建小堆,将第三个模板参数换成greater比较方式,所以要给出完整的定义
	priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
	cout << "修改为greater比较方式小根堆输出:" << endl;
	while (!q2.empty()) {
		cout << q2.top() << " ";
		q2.pop();
	}
}

在这里插入图片描述

1.3、如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中重载>或<运算符

  • 如果要建大堆,需要用户在自定义类型中提供< 的重载。
  • 如果要建小堆,需要用户在自定义类型中提供> 的重载。
#include <vector>
#include <queue>		//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)
	{
		_cout << d._year << "-" << d._month << "-" << d._day;
		return _cout;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	// 大堆,需要用户在自定义类型中提供<的重载
	priority_queue<Date> q1;
	q1.push(Date(2018, 10, 29));
	q1.push(Date(2018, 10, 28));
	q1.push(Date(2018, 10, 30));
	cout << q1.top() << endl;
	// 如果要创建小堆,需要用户提供>的重载
	priority_queue<Date, vector<Date>, greater<Date>> q2;
	q2.push(Date(2018, 10, 29));
	q2.push(Date(2018, 10, 28));
	q2.push(Date(2018, 10, 30));
	cout << q2.top() << endl;
}

1.4、在OJ中的使用

347. 前 K 个高频元素

class Solution {
public:

	//使用仿函数,创建小堆,提供 > 的重载
    struct cmp{
        bool operator()(const pair<int,int>& lt,const pair<int,int>&rt){
            return lt.second>rt.second;
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        vector<int> res;
        unordered_map<int,int> hash;
        for(int i=0;i<nums.size();++i) ++hash[nums[i]];
        priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> pq;
        for(auto it=hash.begin();it!=hash.end();++it){
            pq.push(*it);
            if(pq.size()>k){
                pq.pop();
            }
        }
        while(!pq.empty()){
            res.push_back(pq.top().first);
            pq.pop();
        }
        return res;
    }
};

二、priority_queue的模拟实现

namespace MyPriorityQueue {

	template<class T, class Container = vector<T>, class Compare = less<T> >
	class priority_queue {
	public:
		priority_queue() = default;
		
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last)
		{
			//从下往上建堆
			for (size_t i = (_con.size() - 1 - 1) / 2; i >= 0; i--) {
				AdjustDown(i);
			}

			从上往下建堆
			//for (size_t i = 1; i < _con.size(); i++) {
			//	AdjustUp(i);
			//}
		}
		

		void push(const T& x) {
			_con.push_back(x);
			AdjustUp(_con.size() - 1);
		}
		
		void pop() {
			assert(size() > 0);	
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}

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

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

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

		bool empty() const {
			return _con.empty();
		}
	private:
		void AdjustDown(size_t parent) {
			size_t child = parent * 2 + 1;
			while (child < _con.size()) {
				if (child + 1 < _con.size() && cmp(_con[child],_con[child + 1])) {
					child++;
				}
				if (cmp(_con[parent],_con[child])) {
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else {
					break;
				}
			}
		}
		void AdjustUp(int child) {
			int parent = (child - 1) / 2;
			while (child > 0) {
				if (cmp(_con[parent],_con[child])) {
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else {
					break;
				}
			}
		}
	private:
		Container _con;
		Compare cmp;
	};
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值