生成两个堆:大根堆 和小根堆。
第一个数 默认放入大根堆。
然后一直有数进来,按照以下逻辑放入两个堆中:
把进来的数和大根堆的堆顶比较,如果比堆顶小(=),则放进大根堆中。
如果比堆顶大,则放入小根堆。
每次放入都要检查 当前两个堆得 size的绝对值是否小于等于1, 如果大于一,则把size较大的堆弹出一个元素加入到另外一个堆中。
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
int main(){
priority_queue<int> s;
priority_queue<int,vector<int>,greater<int> > big;
int n;
int help;
while(cin >>n && n!= 0){
if(s.empty()){
s.push(n);
cout<<"now ,the medium is: " << s.top()<<endl;
continue;
}
if(n <= s.top()){
s.push(n);
if( s.size() - big.size() > 1){
help = s.top();
big.push(help);
s.pop();
}
}else{
big.push(n);
if( big.size() - s.size() > 1){
help = big.top();
s.push(help);
big.pop();
}
}
if(s.size() == big.size()){
cout << "now ,the medium is: " << (s.top() + big.top()) /2.0<<endl;
}else if(s.size() > big.size()){
cout << "now ,the medium is: " << s.top() <<endl;
}else{
cout << "now ,the medium is: " << big.top()<<endl;
}
}
return 0;
}
为什么要这样做呢?
我们解析一下:
我们每次进来一个数 都要和大根堆的堆顶比较,比他大的放另一个小根堆里,比他小的放大根堆里,
这样的结果是,小根堆里存的都是比大根堆大的值。
ok,继续:
当我们连续进来都是比大根堆顶大的值,则数据一直加入小根堆,没几次小根堆的元素个数就超过了大根堆,这是出现问题了啊,生病了啊,得治,医生一看发现 : 哦,你大根堆的堆顶元素选的值太小的,需要更新一个更大的值了, 刚好旁边的小根堆里存的都是比 大根堆的堆顶大的值, 取小根堆的堆顶就更棒了,取所有比它大的值中最小的取更新。
另外啊,还顺便调整了双方堆内元素的个数,不是很棒吗。
对于一直进来的都是比大根堆顶小的元素。也是一个意思,说明大根堆的堆顶选的元素太大了,需要换一个更小的,且比他小的都在自己这个堆内,所以把堆顶拿走后,重新得到的堆顶就是比原来刚好小一号的值了,也是很棒的。
这样调整的后果:类似于中位数partition,比它小的都在大根堆里,比他大的都在小根堆里。
算中位数还很方便。
ok 88~~