头文件#include
。
其实就是堆,可以这么说。对于有的问题需要用堆去实现的,就可以用优先队列。
它允许用户为队列中元素设置优先级,放置元素的时候不是直接放到队尾,而是放置到比它优先级低的元素前面,标准库默认使用 < 操作符来确定优先级关系。
priority_queue与queue一样,也是从队尾添加元素,从队头删除元素。因元素放置顺序是按元素优先级来的,所以出队出的是最高优先级的元素。优先队列具有 最高优先级先出的行为特性。
它的原型是:
template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type> > class priority_queue;
第一个为:元素类型
第二个为:承载优先队列的容器类型。默认是vector<>
第三个为:比较函数。带默认是less<>
注:defaultpriority_queue
情况下:优先队列的优先级关系为值大的优先级高、值小的优先级低,而优先级高的放在队列前面,所以对于默认类型,它的内部元素总是从大到小的。
如定义:priority_queue
等价于priority_queue
依次push1-5-8-2-9,一直top取队头元素并pop弹出,直到队空。输出顺序会是:9-8-5-2-1
默认从小到大。值大的数优先级高,放在前面。
如果要改变优先级呢?来按从小到大排呢
这样定义:priority_queue
使用自定义类型,就要重载<运算符
。
#include
#include
using namespace std;
struct BTNode{
int priority;
int value;
bool operator < (const node &a, const node &b) {
return a.priority < b.priority;
}
pq.push(x)
pq.pop()
x=pq.top()
注意:这里与一般的queue不一样,不用front()!!!pq.empty()
pq.size()
关于可以用堆去实现的都可以用优先队列priority_queue。
由于每次出队都是在剩下元素里面最大(小)的,所以只要把数组的元素放到一个priority_queue里,然后依次top+pop,得到的序列就是排序好的。
n个元素做排序,堆大小也为n。不管是插入还是删除操作,每次调整的复杂度为log(n)(堆的高度),所以算法的时间复杂度就是O(nlogn)。有人说,实际使用时候效率比快排归并排序略差,待研究。
找一波数字里面最大的k个数字。
用一个k大小的优先队列。小顶堆,堆顶为整个队列中的最小值
遍历整个数据:
if pq.size()
比较各num和pq.top()的大小,如果大于则替换堆顶,即弹出队头(堆顶),然后插入到堆里面。
之前我在 https://blog.csdn.net/u013317445/article/details/89680330 c++重拾 STL之heap(堆)这篇博客中用heap实现过。今天我用priority_queue优先队列实现一次。
**问题:**如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
思路:
将数据分为两个部分,左半部分、右半部分。
左半部分用大顶堆,保证左半部分数据的最大值在大顶堆的顶部。
右半部分用小顶堆,保证右半部分数据的最小值在小顶堆的顶部。
当数据总数为偶数时候,将来的num加入到右半部分,
总数为奇数时候,将来的num加入到左半部分。
整个数据流的中位数就看堆顶。
更具体点,当数据总数为偶数时候,为两部分堆顶的平均值,
为奇数时候,就是左半部分的堆顶。
调整:
1、当总数偶数时,本计划来的数加入到右半部分(小顶堆)。
但是如果来的数字比大顶堆的最大值还小,所以理应加入到左半部分(大顶堆),
但是左半部分又多了一个数,所以左半部分删除最大值,并将其添加到右半部分(小顶堆),来保证左右部分数字个数平分。
否则的话,来的数就直接加入到右半部分。
2、当总数为奇数时,本计划...但... 同理。
class Solution {
private:
priority_queue<int, vector<int>, less<int>> max;//大顶堆(左半部分,堆顶要为左的最大值)
priority_queue<int, vector<int>, greater<int>> min;//小顶堆(右半部分,堆顶要为右的最小值)
public:
void Insert(int num)
{
if( ((max.size()+min.size())&1) ==0){//总数为偶数
int maxNum= max.top();//即大顶堆的最大值(左半部分的最大值)
if(max.size()>0 && num < maxNum){//犯错:必须写上max.size()>0 后面要max.pop()呀
max.push(num);
min.push(max.top());
max.pop();
}else{
min.push(num);
}
}else{//总数为奇数,本计划加入到左半部分... .. 和上面同理
int minNum= min.top();//即小顶堆的最小值(右半部分的最小值)
if(min.size()>0 && num > minNum){ //犯错:必须写上min.size()>0
min.push(num);
max.push(min.top());
min.pop();
}else{
max.push(num);
}
}
}
double GetMedian()
{
//下面这个一直报错,段错误 下面的code不就多了一个定义double吗?问题到底在哪里 还少考虑了什么情况呢?
// if((max.size()+min.size())==0) return 0;
// return ((max.size()+ min.size())&1 )==0 ? (max.top()+min.top())/2.0 : max.top();//必须是2.0 不是2
double median=0;
if((max.size()+min.size())==0)
return 0;
if(((max.size()+min.size()) &1)==0)
{
median= (max.top()+min.top())/2.0;//2.0 或者给分子的每一个加强转(double)
}else
{
median= min.top();
}
return median;
}
};