学习历程-数据流的中位数

原题

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

解读,

有一个会不断增长的数据,一直在添加新的数。需要求的每次新加数后,求整体的中位数(从第一个数开始到新的数)
例如
输入 1
中位数 1
再输入 2
中位数 1.5
再输入 3
中位数 2
再输入 0
中位数 0.5

class Solution {
    /*
    后来的数会和前面的数比较,来确定位置,所以需要保存全部的数
    而中位数只需要最中间的数(一个或两个)
    所以只需要确定中间的数的值,
    直接排序所有数效率比较差,用堆排序速度更快。因为只需要知道前(后)一半中的最大(小)值,不是全部的顺序
    这样,对每个新的值,判断其放在哪个堆(放在前半还是后半)
    如果某个值放入后,两个部分差值大于1,也就说明某个部分不是只占一半了,那就拿走一个(堆顶)给另外一个堆,再重新取得堆顶
    中位数中,偶数个取平均值,直接计算即可,奇数个时根据设定,哪个堆多一个,就取哪个堆的堆顶
    直接设定某个堆天生可以比另外一个多1最好。
    */
    priority_queue<int, vector<int>, less<int> > p;//大顶堆 队列,用来保存前半部分(小的数)
    priority_queue<int, vector<int>, greater<int> > q;//小顶堆 队列,用来保存后半部分(大的数)

public:
    //插入操作
    void Insert(int num) {
        if (p.empty())//堆为空,保存到可以多一的队列中
        {
            p.push(num);
        }
        else if (num > p.top())//如果新的数比 前半部分中最大值还大,那么就将其加入后半部分
        {
            q.push(num);
        }
        else {//否则加入前半部分
            p.push(num);
        }
        if (p.size() == q.size() + 2)//如果连续多个(平衡后两个)数都加入了前半部分,那就取前半部分的堆顶,放入后半部分
        {
            q.push(p.top());
            p.pop();
        }
        else if (p.size() == q.size() - 1)//如果连续多个数都加入了后半部分,那就取后半部分的堆顶,放入前半部分。这个例子中,设定前仅半部分可以比后半多一个,所以当后半多1个的时候就放入前半
        {
            p.push(q.top());
            q.pop();
        }
    }
    //获取当前平均值
    double GetMedian() {
        return p.size() == q.size() ? (p.top() + q.top()) / 2.0 : p.top();//根据总数显示,两半总数相等,那就代表总数时偶数。取两个堆顶平均值,否则哪个比另外一个多一取哪个堆顶。例子中设定前半部分可以多一个,所以直接取前半部分堆顶
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值