【剑指offer】面试题41 数据流中的中位数

面试题–【剑指Offer】 题目解答

题目要求

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

解题分析

这道题我们用最大堆,最小堆来实现。
需要注意的是
1、两个堆中的数据数目差不能超过1,这样可以使中位数只会出现在两个堆的交接处;
2、保证大顶堆的所有数据都小于小顶堆,这样就满足了排序要求。
实现的细节
(1)当目前元素总数是偶数时,我们把下一个新元素放到最小堆里;如果当前元素的总数是奇数,那么下一个元素放在最大堆里。
(2)并且保证最大堆元素都小于最小堆。

根据上面这一点,我们会发现一个情况就是当目前元素总数是偶数时,我们应该把下一个新元素放到最小堆里,但是如果这个新元素要比最大堆的某些数还小怎么办?把他放在最小堆那么就不能保证“最大堆元素都小于最小堆”。所以我们在执行存放数据之前要进行判断,如果这个新元素要比最大堆的某些数还小,那么就把他先放到最大堆里面,然后把最大堆的堆顶元素弹出再放到最小堆,这样就可以继续保证最大堆元素都小于最小堆

当目前元素总数是奇数时,我们应该把下一个新元素放到最小堆里,这个过程和上面的类似,就不过多赘述了,大家可以自己结合代码思考一下。

这样排完之后的中位数就是,如果整体总数是奇数那么结果就是最小堆的堆顶元素,如果整体总数是偶数那么结果就是最大,最小堆的堆顶元素的平均数。

主要代码c++

// 最大堆,最小堆
// 最大堆对应的数组,最小堆对应的数组
class Solution {
public:
    void Insert(int num)
    {
        if(((max.size()+min.size()) & 1) == 0) //如果现在总数是偶数那么下一个元素num分配到最小堆
        {
            if(max.size()>0 && num < max[0]) //保证最大堆的元素 都小于最小堆
            {
                max.push_back(num);
                push_heap(max.begin(),max.end(),less<int>());//创建最大堆
                
                num = max[0];
                pop_heap(max.begin(),max.end(),less<int>()); //弹出最大堆的最大元素(栈顶)
                max.pop_back();
            }
            min.push_back(num);
            push_heap(min.begin(),min.end(),greater<int>());
        }
            else //如果现在总数是奇数那么下一个元素num分配到最大堆
            {
             if(min.size()>0 && num > min[0]) //保证最小堆的元素 都大于最大堆
             {
                 min.push_back(num);
                 push_heap(min.begin(),min.end(),greater<int>());
                 
                 num = min[0];
                 pop_heap(min.begin(),min.end(),greater<int>());
                 min.pop_back();
             }
             max.push_back(num);
             push_heap(max.begin(),max.end(),less<int>());
            }
        }
    double GetMedian()
    { 
        int size = max.size() + min.size();
        if(size<=0) //没有元素,抛出异常
                return 0;
        if((size & 1) == 1)
            return min[0];
        else
            return (min[0]+max[0]) / 2.0;
       
    }
private:
   vector<int>max;
   vector<int>min;
};

注意

刚开始写的时候遇到一个错误就是忘记了位与运算的优先级没有赋值高,所以一直在报错!记录一下。

你可能感兴趣的:(剑指offer)