cdoj 2015数据结构专题:F - 秋实大哥与妹纸

致中和,天地位焉,万物育焉。秋实大哥是一个追求中庸的人。

虽然秋实大哥的仰慕者众多,但秋实大哥不喜欢极端的妹纸。所以他想从所有仰慕自己的妹纸中挑选出一个符合中庸之道的。

每一个妹纸对秋实大哥的仰慕程度可以用一个整数 ai 来表示,秋实大哥想要找出这些数的中位数。

计算有限个数的数据的中位数的方法是:

把所有的同类数据按照大小的顺序排列。如果数据的个数是奇数,则中间那个数据就是这群数据的中位数;
如果数据的个数是偶数,则中间那2个数据的算术平均值就是这群数据的中位数。

Input

第一行有一个整数 n ,表示秋实大哥的仰慕者数目。

接下来 n 行,每行有一个正整数 ai

1n250000 1ai<231

Output

输出这 n 个数的中位数,保留一位小数。

Sample input and output

Sample Input Sample Output
3
1
2
3
2.0

Hint

注意内存大小限制。


用小根堆实现。思想和用优先队列一样,但是优先队列会爆内存,所以手写堆。= =

如果将所有数排序,那么中位数一定在前一半多一个或者后一半多一个中,所以找中位数就只用用一半大小的数组存就好了。

读入一半多一个的数据后,之后每在堆中加一个数,再删掉堆中最小的。最后堆顶即为中位数。如果是偶数个,再加上下一层中小的取平均值即可。


#include <iostream>
#include <cstdio>

#define lid (fa << 1)
#define rid (fa << 1 | 1)
using namespace std;

unsigned int l[125005] = {0};

void push(unsigned int x)
{
    l[0]++;
    int fa = l[0];
    l[fa] = x;
    while(fa / 2 > 0){
        if(l[fa / 2] > l[fa]){
            int temp = l[fa];
            l[fa] = l[fa / 2];
            l[fa / 2] = temp;
            fa = fa / 2;
        }
        else
            break;
    }
}

int down(int x)
{
    int fa = x;
    int temp;
    int flag;
    while(1){
        if(rid > l[0] && lid <= l[0] && l[fa] > l[lid]){
            temp = l[lid];
            l[lid] = l[fa];
            l[fa] = temp;
            fa = lid;
            if(fa == 2)
                return 1;
        }
        else if(rid > l[0] && lid <= l[0]) break;
        else if(rid <= l[0] && lid <= l[0]){
            if(l[fa] <= l[lid] && l[fa] <= l[rid])
                break;
            else if(l[fa] > l[lid] && l[lid] <= l[rid]){
                temp = l[lid];
                l[lid] = l[fa];
                l[fa] = temp;
                fa = lid;
            }
            else if((l[fa] > l[rid] && l[rid] <= l[lid])){
                temp = l[rid];
                l[rid] = l[fa];
                l[fa] = temp;
                fa = rid;
            }
        }
        else    break;
    }
    return fa;
}

void pop()
{
    int temp = l[l[0]];
    l[l[0]] = l[1];
    l[1] = temp;
    l[0]--;
    while(1){
        int flag = down(1);
        if(flag == 1)
            break;
    }
}

int main()
{
    int n,t;
    unsigned int x;
    double out;
    scanf("%d",&n);
    t = n / 2 + 1;
    for(int i = 0; i < t; i ++){
        scanf("%u",&x);
        push(x);
    }
    for(int i = t; i < n; i ++){
        scanf("%u",&x);
        push(x);
        pop();
    }
    if(n % 2 == 1){
        out = (double) l[1];
        printf("%.1lf",out);
    }
    else{
        if(n == 2)
            out = (double) l[2] / 2;
        else if(l[2] < l[3])
            out = (double) l[2] / 2;
        else
            out = (double) l[3] / 2;
        out += (double) l[1] / 2;
        printf("%.1lf",out);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值