題目描述:
如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用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];
}
}
};