优先级队列


在刷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;
    }
};
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木子v

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值