20180601
题目:
如何得到一个数据流中的中位数?如果从数据流中读取奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序后中间两个数的平均数
解题思路:
1.本来使用一个AVL树来实现是最佳的,但是各种语言的函数库都还没有现成的AVL树的实现,所以选择使用两个堆来完成。使用一个最大堆实现中位数左边的数据容器,使用一个最小堆实现中位数右边的数据容器。往堆中插入一个数据的时间是O(logn),而取得最大最小数据的时间是O(1)。
注意:
1.必须保证数据平均分配到两个堆中间,即两个堆中的数据数目之差不能超过1。为了实现数据的平均分配,可以在数据的总数目是偶数是把新数据插入到最小堆中,否则插入到最大堆中。
2.还必须保证最小堆中的所有数据都要大于最大堆中的数据。比如在偶数个数据时,如果要插入的数据小于最大堆的一些数据,需要把数据先插入最大堆,然后把最大堆的最大数据弹出,再插入到最小堆中。奇数个数的数据插入时也相同。
3.在《剑指offer》的标准解法中,使用了STL函数push_heap,pop_heap等。 STL中heap相关函数的用法
C++代码实现(可AC)
//和《剑指offer》上的思路一样,不过改成了第偶数个数据加入最小堆,第奇数个数据加入最大堆
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class toGetMedian{
public:
void Insert(int num)
{
int size = maxheap.size() + minheap.size();
if(size&1){ //第偶数个的情况
int tmp = num;
if((!maxheap.empty())&&(num < maxheap[0])){
tmp = maxheap[0];
maxheap[0] = num;
make_heap(maxheap.begin(),maxheap.end());
}
minheap.push_back(tmp);
push_heap(minheap.begin(),minheap.end(),greater<int>());
}
else{
int tmp = num;
if((!minheap.empty())&&(num > minheap[0])){
tmp = minheap[0];
minheap[0] = num;
make_heap(minheap.begin(),minheap.end(),greater<int>());
}
maxheap.push_back(tmp);
push_heap(maxheap.begin(),maxheap.end());
}
}
double GetMedian()
{
int size = maxheap.size() + minheap.size();
double resu;
if(size & 1){
resu = maxheap[0];
}
else{
resu = (maxheap[0] + minheap[0])/2.;
}
return resu;
}
private:
vector<int> maxheap;
vector<int> minheap;
};
int main()
{
toGetMedian test;
test.Insert(1);
test.Insert(9);
test.Insert(3);
test.Insert(6);
test.Insert(20);
test.Insert(82);
cout << test.GetMedian() << endl;
return 0;
}