在刷leetcode 347. 前K个高频元素时,用到了优先级队列的相关知识,在此记录一下。
优先队列的底层实现是大顶堆或小顶堆。
注意:这里我们不需要进行排序,即我们不是利用堆排序的排序功能,而是利用堆的调整的功能[如果是大顶堆,堆会将元素调整成大顶堆(堆顶元素最大);如果是小顶堆,堆会将元素调整成小顶堆(堆顶元素最小)]。
头文件
#include<queue>
定义
priority_queue<Type, Container, Functional>;
Type是要存放的数据类型,
Container是实现底层堆的容器,必须是数组实现的容器,如vector、deque,
Functional是比较方式/比较函数/优先级。
priority_queue<Type>;
此时默认的容器是vector,默认的比较方式是大顶堆less<type>
如何使用?
1、基本类型做优先级队列元素的例子
priority_queue<int,vector<int>,greater<int>> pri_que;//小顶堆
priority_queue<int,vector<int>,less<int>> pri_que;//大顶堆
priority_queue<int> pri_que;//默认大顶堆
2、用pair做优先级队列元素的例子
先比较frist,如果frist相等,那么就比较second
//pair
priority_queue<pair<int, int>> a;
pair<int, int> b(1, 2);
pair<int, int> c(1, 3);
pair<int, int> d(2, 5);
a.push(d);
a.push(c);
a.push(b);
while (!a.empty()) {
cout << a.top().first << ' ' << a.top().second << '\n';
a.pop();
}
//输出结果为:
2 5
1 3
1 2
3、自定义比较方式
当数据类型并不是基本数据类型,而是自定义的数据类型时,就不能用greater或less的比较方式了,而是需要自定义比较方式
在此自定义数据类型fruit
class fruit{
sting name;
int price;
};
有两种自定义比较方式的方法,如下
3.1 重载运算符
如果希望水果价格高为优先级高
//大顶堆
class fruit{
string name;
int price;
friend bool operator < (fruit f1,fruit f2)
{
return f1.peice < f2.price;
}
};
如果希望水果价格低为优先级高
//小顶堆
class fruit{
string name;
int price;
friend bool operator < (fruit f1,fruit f2)
{
return f1.peice > f2.price; //此处是>
}
};
3.2 仿函数
如果希望水果价格低为优先级高
//大顶堆
class myComparison
{
bool operator () (fruit f1,fruit f2)
{
return f1.price < f2.price;
}
};
//此时优先级队列的定义应该如下
priority_queue<fruit,vector<fruit>,myComparison> pri_que;
优先级队列中常用函数
top()//返回队头元素(堆顶元素)
pop()//删除队头元素(堆顶元素)
push(elem)//在队尾插入一个元素elem
empty()//判断队列是否为空
size()//返回队列中元素的个数
优先级队列解决top-K问题
https://leetcode.cn/problems/top-k-frequent-elements/
代码如下:
//本题主要涉及三部分内容:
//1.统计不同元素出现的频率
//2.对频率排序
//注意:我们应该使用小顶堆,这样我们每次都把较小的元素从堆顶弹出,最后小顶堆里留下的才是前k个最大元素
//3.找出前K个高频元素
class Solution {
public:
class myCompairson {//使用仿函数自定义优先级队列的比较方式
public:
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second > rhs.second;
}
};
static vector<int> topKFrequent(vector<int>& nums, int k) {
//统计元素出现的频率
unordered_map<int, int> map; //map<nums[i], 元素出现的次数>
for (int i = 0; i < nums.size(); i++) {
map[nums[i]]++;
}
priority_queue<pair<int, int>, vector<pair<int, int>>, myCompairson> pri_que;
//用固定大小为k的小顶堆,扫描所有频率的数值
for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
pri_que.push(*it);
if (pri_que.size() > k) {
pri_que.pop();
}
}
//找出前k个高频元素,因为小顶堆首先弹出的是最小元素,所以要倒序输出到数组中
vector<int> result(k, 0);
for (int i = k - 1; i >= 0; i--) {
result[i] = pri_que.top().first;
pri_que.pop();
}
return result;
}
};