题目描述:
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
解题思路:
本题对数据流求取中位数,要考虑数据插入数据结构和求取中位数的时间开销;本文利用vector数组,采用大顶堆和小顶堆的数据结构存储数据流,如果数据流是偶数,则大顶堆和小顶堆的元素数量相同,如果是奇数,小顶堆的元素比大顶堆的元素个数多1;小顶堆的最小值(开头处)比大顶推的最大值(开头处)大;这样中位数的获取,如果是奇数,就是小顶推的最小值(开头处),否则是(小顶堆的最小值+大顶推的最大值)/2。整个算法,插入数据的时间开销是O(logn),获取中位数的时间开销为O(1);
注意:
1)push_heap(),pop_heap(),make_heap(),sort_heap()的用法参考https://blog.csdn.net/qq_34793133/article/details/81222919
2)less<T>() 对于vector模拟堆而言表示大顶堆,greater<T>()表示小顶堆;
而对set,multiset而言 less<T>()表示小顶堆,greater<T>()表示大顶堆。
通过的C++代码:
class Solution {
public:
vector<int> bigTopHeap;
vector<int> smallTopHeap;
void Insert(int num)
{
if(((bigTopHeap.size() + smallTopHeap.size()) & 1) == 0)
{
if(bigTopHeap.size() > 0 && num < bigTopHeap[0])
{
bigTopHeap.push_back(num);
push_heap(bigTopHeap.begin(), bigTopHeap.end(), less<int>());
num = bigTopHeap[0];
pop_heap(bigTopHeap.begin(), bigTopHeap.end(),less<int>());
bigTopHeap.pop_back();
}
smallTopHeap.push_back(num);
push_heap(smallTopHeap.begin(), smallTopHeap.end(), greater<int>());
}
else
{
if(smallTopHeap.size() > 0 && num > smallTopHeap[0])
{
smallTopHeap.push_back(num);
push_heap(smallTopHeap.begin(), smallTopHeap.end(), greater<int>());
num = smallTopHeap[0];
pop_heap(smallTopHeap.begin(), smallTopHeap.end(), greater<int>());
smallTopHeap.pop_back();
}
bigTopHeap.push_back(num);
push_heap(bigTopHeap.begin(), bigTopHeap.end(), less<int>());
}
}
double GetMedian()
{
int cout = bigTopHeap.size() + smallTopHeap.size();
if(cout == 0)
return 0.0;
//throw exception("No numbers are avilable");
if((cout & 1) == 0)
{
return (bigTopHeap[0]+smallTopHeap[0])/2.0;
}
else
{
return smallTopHeap[0];
}
}
};