剑指offer--面试题41:数据流中的中位数

题目

        如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。

如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

 

思路


        采用大根堆+小根堆结合的方法,且满足:

        ① 两个堆中的数据数目差不能超过1,这样可以使中位数只会出现在两个堆的交接处;

        ② 大顶堆的所有数据都小于小顶堆,这样就满足了排序要求。

      (左边大顶堆,右边小顶堆)

 

        1、插入的思路:

              1)若已读取的个数为偶数(包括0)时,两个堆的数目已经相同,将新读取的数插入到小顶堆中,从而实现小顶堆的个数多一。但是,如果新读取的数字比大顶堆中最大的数字还小,就不能直接插入到小顶堆中了 ,此时必须将新数字插入到大顶堆中,而将大顶堆中的最大数字插入到小顶堆中,从而实现小顶堆的个数多一。

         2)若已读取的个数为奇数时,小顶堆的个数多一,所以要将新读取数字插入到大顶堆中,此时方法与上面类似。

 

        2、取中位数的思路:

             ① 当总个数为偶数时,使两个堆的数目相同,则中位数=大顶堆的最大数字与小顶堆的最小数字的平均值;

             ② 而总个数为奇数时,使小顶堆的个数比大顶堆多一,则中位数=小顶堆的最小数字。

 

#include <cstdio>
#include <algorithm>
#include <vector>
#include <functional>

using namespace std;

template<typename T> class DynamicArray
{
public:
    void Insert(T num)
    {
        if(((min.size() + max.size()) & 1) == 0)//保证两个堆的size差<=1,size和为奇数时插进minHeap
        {
            if(max.size() > 0 && num < max[0])//保证最小堆的数 都大于 最大堆。
            {
                max.push_back(num);
                push_heap(max.begin(), max.end(), less<T>());

                num = max[0];

                pop_heap(max.begin(), max.end(), less<T>());
                max.pop_back();
            }

            min.push_back(num);
            push_heap(min.begin(), min.end(), greater<T>());
        }
        else
        {
            if(min.size() > 0 && min[0] < num)
            {
                min.push_back(num);
                push_heap(min.begin(), min.end(), greater<T>());

                num = min[0];

                pop_heap(min.begin(), min.end(), greater<T>());
                min.pop_back();
            }

            max.push_back(num);
            push_heap(max.begin(), max.end(), less<T>());
        }
    }

    T GetMedian()
    {
        int size = min.size() + max.size();
        if(size == 0)
            throw exception("No numbers are available");

        T median = 0;
        if((size & 1) == 1)
            median = min[0];
        else
            median = (min[0] + max[0]) / 2;

        return median;
    }

private:
    vector<T> min;
    vector<T> max;
};


 

关于push_heap和pop_heap的使用

 

make_heap:根据不同参数生成大顶堆或者小顶堆,默认大顶堆。
make_heap(_RAIter,_RAIter) 默认生成大顶堆
make_heap(_RAIter,_RAIter,_Compare) _Compare有两种参数,一种是greater(生成小顶堆),一种是less(生成大顶堆)

 


push_heap()是向堆中插入一个元素,并且使堆的规则依然成立
push_heap(_RAIter,_RAIter) 默认为大顶堆
push_heap(_RAIter,_RAIter,_Compare) _Compare有两种参数,一种是greater(小顶堆),一种是less(大顶堆)


调用push_heap之前必须调用make_heap创建一个堆
         首先数组push_back插入元素,然后再调用push_heap,它会使最后一个元素插到合适位置
注意,push_heap中的_Compare和make_heap中的_Compare参数必须是一致的,不然会插入堆失败,最后一个元素还是在最后位置,导致插入失败

 

pop_heap()是在堆的基础上,弹出堆顶元素。
pop_heap(_RAIter,_RAIter) 默认为大顶堆
pop_heap(_RAIter,_RAIter,_Compare) _Compare有两种参数,一种是greater(小顶堆),一种是less(大顶堆)
比如pop_heap(nums.begin(), nums.end(),greater<int>()),它会将堆顶元素(即为数组第一个位置)和数组最后一个位置对调,然后你可以调用数组pop_back,删除这个元素
注意,pop_heap中的_Compare和make_heap中的_Compare参数必须是一致的,不然会失败
 

使用的时候可以不make_heap,而直接push_heap,示例如这道剑指offer上的题目数据流中的中位数

 

若用make_heap(), pop_heap(), push_heap(),需要添加头文件# include <algorithm> 。
用less ()和greater () 需要添加头文件 # include <functional> 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潇湘夜雨~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值