数据流中的中位数

1、题目描述

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

2、代码

2.1 原理:用两个堆实现,左边是做大堆,右边是最小堆,当数据总数是偶数的时候,中位数是两个堆首元素和的一半;当数据是奇数的时候,可以约定取最大堆或者是最小堆的首元素。
2.2 思路:中位数是一串数据中大小排在正中间的数,那么排到中位数左边的数都比中位数小,右边的比中位数大,因此,只需要实时将当前数据分为两堆,左边一堆的最大值比右边最小堆的最小值要小,中位数就有左边堆的最大和右边堆的最小决定。这样,求中位数只需要实时记录左右两堆数据的最大和最小值即可,那么用最大最小堆即可实现。

最大最小堆需要满足的条件:
(1)最大最小堆任何时候元素个数之差不能大于1
(2)左边最大堆的元素最大元素不能大于右边最小堆的最小元素,以保证数据的有序性。

2.3 代码:

#include
#include
#include
#include
using namespace std;

class Solution {
public:
    vector<int> minHeap;
    vector<int> maxHeap;
    void Insert(int num)
    {
      //如果之前是偶数个数据  --插入最小堆栈
        int data = (minHeap.size()+maxHeap.size())&1;
        if(((minHeap.size()+maxHeap.size())&1)==0)
        {
            //如果当前数比最大堆的首元素要小
            if((!maxHeap.empty())&&(num<=maxHeap[0]))
            {
                maxHeap.push_back(num);
                push_heap(maxHeap.begin(), maxHeap.end(),less<int>());

                pop_heap(maxHeap.begin(), maxHeap.end(),less<int>());
                num = *(maxHeap.end()-1);
                maxHeap.pop_back();
            }
            //再向最小堆添加元素
            minHeap.push_back(num);
            push_heap(minHeap.begin(), minHeap.end(), greater<int>());   //最小堆
        }
        //之前是奇数个数,将当前元素插入到最大堆
        else
        {
            //当前元素大于最小堆的首元素
            if(!minHeap.empty() && num >= minHeap[0])
            {
                minHeap.push_back(num);
                push_heap(minHeap.begin(), minHeap.end(), greater<int>());

                pop_heap(minHeap.begin(), minHeap.end(), greater<int>());
                num = *(minHeap.end()-1);
                minHeap.pop_back();
            }
            //再向最大堆插入元素
            maxHeap.push_back(num);
            push_heap(maxHeap.begin(), maxHeap.end(), less<int>());
        }
    }

    double GetMedian()
    { 
        if(((minHeap.size()+maxHeap.size())&1)==0)
        {
            if(maxHeap.size()==0 || minHeap.size()==0)
                return 0;
            else
                return (maxHeap[0]+minHeap[0])*1.0/2;
        }
        else
            return minHeap[0];
    }
};

注意:
(1)当当前总的数据个数是偶数的时候,直接取最大堆和最小堆的首元素的均值就是最后的中位数。如果是奇数,那么就与之前约定的插入的时候的顺序有关,这点需要对应起来。
(2)当一个数据按照当前数据个数的奇偶性应该插入到最大堆的时候,如果当前数值大于最小堆的最小值,如果将该数直接插入最大堆,上述条件2不满足,解决办法是现将该数插入最小堆,再将最小堆的最大值弹出并插入到最大堆;同理,当一个应该插入最小堆,但是其值小于最大堆的最大值的时候,处理思路一样。

3、pop_back/push_back,push_heap/pop_heap的区别

3.1 back系列和heap系列的区别:
back系列是操作容器元素添加和删除的方法,heap是堆排序的方法。不要混淆。
3.2 pop_back VS push_back
pop_back将一个容器的最后一个元素删除,push_back是往容器最后添加一个元素。 两者一般都没有返回值。
3.3 push_heap/pop_heap的区别
(1)push_heap是在容器添加一个元素后,将其堆排序,less()对应最大堆排序,greater()对应最小堆排序。less和greater定义在头文件中。该方法一般用在向容器最后添加了元素之后。
(2)pop_heap是将当前容器的第一元素移到最后,并将剩余的元素堆排序。less()对应最大堆排序,greater()对应最小堆排序,同之前。
关于更多这方面的讲解见博客:
http://blog.csdn.net/whistlena/article/details/52032067

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