题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
有以下几个思路
数据结构 | 插入的时间效率 | 得到中位数的时间效率 |
---|---|---|
没有排序的数组 | O(1) | O(n) |
排序的数组 | O(n) | O(1) |
排序的链表 | O(n) | O(1) |
二叉搜索树 | 平均O(lgn)最差O(n) | 平均O(lgn)最差O(n) |
AVL树 | O(lgn) | O(1) |
最大堆和最小堆 | O(lgn) | O(1) |
AVL数结构复杂,插入删除操作太难写了,可以使用最大堆和最小堆进行可以使用vector和make_heap进行操作。把数据分为两部分,前半段为最大堆,后半段为最小堆,如果元素综合为偶数插入前半段组成最大堆,否则插入后半段组成最小堆,假如插入前半段时,插入的值比后半段的最小值大,那么就让这个数和后半段的最小值互换,并重构后半段的最小堆。插入前半段也是如此。在取出中位数时,如果元素个数为奇数个,直接取出前半段的最大值,否则取出前半段的最大值和后半段的最小值。
可以看代码注释
class Solution {
public:
void Insert(int num)
{
if((min.size()+max.size())%2==0) // 保证前半段和后半段的平衡,元素数目为偶数时,插入前半段
{
if(!(min.empty()||num<=min[0]))
{
int temp=num;
num=min[0];
min[0]=temp;
make_heap(min.begin(),min.end());//元素交换后必须立刻重建最小堆
}
max.push_back(num);
make_heap(max.begin(),max.end());
}
else
{
if(!(max.empty()||num>=max[0]))
{
int temp=num;
num=max[0];
max[0]=temp;
make_heap(max.begin(),max.end());//交换后必须立刻构建最大堆
}
min.push_back(num);
make_heap(min.begin(),min.end(),greater<int>());
}
}
double GetMedian()
{
if(min.empty()&&max.empty())
throw exception("NO numbers are available");
if(min.empty())
return max[0];
double res=0.0;
if((min.size()+max.size())%2==1){
res=static_cast<double>(max[0]);
}
else
{
res=(static_cast<double>(max[0])+static_cast<double>(min[0]))/2.0;//返回double类型 进行转换
}
return res;
}
private:
vector<int> max;
vector<int> min;
};