数据流中的中位数
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
题目要求实时在插入的过程中得到当前数据流的中卫数,这里要利用到顶堆的概念:
顶堆结构实际上为二叉树的结构,这里当作数组看待比较容易理解,并且是一个二叉排序树,排序的规则为:
大顶堆–根节点值定大于子节点,转换为数组可理解为0号位置元素最大,且降序排列;
小顶堆–根节点值定小于子节点,转换为数组可理解为0号位置元素最小,且升序排列;
这道题的思路就是在插入过程中不断更新顶堆的存储内容,在取中位数时,直接取两顶堆头部元素平均值即可
需要比较细心的考虑很多种情况
priority_queue<int, vector<int>, less<int>> big;
priority_queue<int, vector<int>, greater<int>> small;
void Insert(int num)
{
//每个数先放小顶堆中,考虑若此时大小顶堆size相同,一个很小的数放入小顶堆中会导致中位数计算错误
//对于这种情况如何避免,始终让大顶堆size大于等于小顶堆,返回大顶堆top
if(big.empty() || num < big.top()) big.push(num);//保证大顶堆头部为中位数
else small.push(num);
if(big.size() - small.size() == 2) {
small.push(big.top());
big.pop();
}
if(small.size() - big.size() == 1){
big.push(small.top());
small.pop();
}
}
double GetMedian()
{
return small.size()==big.size()? (small.top()+big.top())/2.0 : big.top();
}