[数据结构] 对顶堆求中位数

中位数求法比较多 离线的我不会

比较容易实现的就是 在线的对顶堆

对顶堆的定义:

  • 小顶堆存 大于小顶堆堆顶所有元素
  • 大顶堆存 小于大顶堆堆顶所有元素

那么 小顶堆和大顶堆堆顶 就是整个 当前数据元素分界线

并且 堆顶对换/互相插入 不影响定义性质

那么当求中位数时 只需调堆即可

得益于堆的性质 每次调堆时间复杂度为log(n)

1. 当前总元素量为奇数时

只要保证 大顶堆元素比小顶堆元素多一 则中位数为大顶堆堆鼎

同理 只要保证 小顶堆元素比大顶堆元素多一 则中位数为小顶堆堆顶

2.当前总元素量为偶数时

只要保证大顶堆元素等于小顶堆 则中位数为(大顶堆顶 + 小顶堆顶) / 2.0

例题及代码

https://www.luogu.org/problemnew/show/P1168

/*
    Zeolim - An AC a day keeps the bug away
*/

//pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <sstream>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
using namespace std;
using namespace std;
typedef long long ll;

const int MAXN = 1e6 + 7;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);     cout.tie(0);

    priority_queue <ll, vector<ll>, greater<ll> > smalp;
    priority_queue <ll> bigp;
    
    vector <ll> ans;
    
    int len;
    
    cin >> len;
    
    for(int i = 1, x; i <= len; i++)
    {
        cin >> x;
        
        if(i == 1)            //不需求中位数时只需按定义插堆即可
            smalp.push(x);
        
        else if(x > smalp.top())
            smalp.push(x);
        else
            bigp.push(x);
        
        if(i & 1)            //当需要求中位数时调堆
        {
            if(smalp.size() > bigp.size())
                while(smalp.size() != bigp.size() + 1)
                    bigp.push(smalp.top()), smalp.pop();
                    
            else
                while(smalp.size() != bigp.size() + 1)
                    smalp.push(bigp.top()), bigp.pop();
 
            ans.push_back(smalp.top());
        }                  
    }
    
    for(int i = 0; i < ans.size(); i++)
    {
        cout<<ans[i]<<'\n';
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/Zeolim/article/details/88656171