您的位置:首页 > Web前端

牛客网刷题笔记--剑指offer(数据流中的中位数)

2016-08-24 10:46 387 查看
题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

剑指offer给出的思路是:

用两个堆,一个大顶堆,一个小顶堆,若两个堆的元素个数之和为偶数,那中位数为两个堆顶元素值的平均,若个数和为基数,则中位数为小顶堆的顶。

逻辑为:1 先判断两个堆的元素个数是否相等,若想等,则将数字插入到小顶堆中

1.1 再对插入的数字做一个判断,若该数字比大顶堆的最大值还要小,那在小顶堆的中位数可能要改变了,这个值会编程大顶堆的最大值,因此,取出大顶堆的最大值,插入到小顶堆中。

2 若两个堆的元素个数不相等,也就是说现在的中位数在小顶堆上,这次需要将被插入的数字插入到大顶堆中

2.1 若插入的数字大于小顶堆的最小值,那大顶堆的最大值应该是包含该数字的小顶堆的最小值,找到小顶堆的最小值,取出插入到大顶堆中。

上述为插入操作。

对于取中位数,那就方便多了。做一次判断,如果两个堆的元素个数和为奇数,中位数为小顶堆的最小值;若两个堆的元素个数为偶数,中位数为两个堆堆顶元素值的平均值。

代码粘贴如下:

class Solution {
public:
void Insert(int num)
{
if ( ((min.size() + max.size()) & 1) == 0) {
if (max.size() > 0 && num < max[0]) {
max.push_back(num);
make_heap(max.begin(), max.end(), less<int> ());
num = max[0];
pop_heap(max.begin(), max.end(), less<int> ());
max.pop_back();
}
min.push_back(num);
make_heap(min.begin(), min.end(), greater<int> ());
}
else {
if (min.size() > 0 && num > min[0]) {
min.push_back(num);
make_heap(min.begin(), min.end(), greater<int> ());
num = min[0];
pop_heap(min.begin(), min.end(), greater<int> ());
min.pop_back();
}
max.push_back(num);
make_heap(max.begin(), max.end(), less<int> ());
}
}

double GetMedian()
{
int size = min.size() + max.size();
if (size == 0)
return 0.0;
double median = 0;
if ((size & 1) == 1)
median = min[0];
else median = (max[0] + min[0]) / 2.0;
return median;
}
private:
vector<int> min;
vector<int> max;
};


这里的make_heap()函数是用来生成堆的,第三个参数less和greater分别表示生成大顶堆和小顶堆,堆顶为数组下标为零的元素。

pop_heap()是将数组零下标元素和数组最后一个元素进行交换,忽略最后一个元素,对剩余的元素进行调整,生成堆。所以还需要用pop_back()函数来删除掉不需要的元素。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息