zerofly's Blog

努力不一定成功,但不努力一定不会成功

0%

数据流中的中位数


题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

解题思路

可以通过构造两个堆来实现求取中位数的目的。

构造大顶堆在左,小顶堆在右。且两个堆中的元素之差不大于1. 大顶堆的最大值,小于小顶堆的最小值,从而保证,大顶堆在的左半部分的值始终小于右半部分。

image-20200608215134086

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Solution
{
public:
void Insert (int num)
{
int size = min.size() + max.size();
if ((size & 1) == 0) // 若当前元素个数为偶数,则将值插入小顶堆
{
if (max.size() > 0 && max[0] > num)
{
max.push_back(num); // 将值插入到大顶堆
push_heap(max.begin(), max.end(), less<int>());//加入新元素后,大顶堆重新排序
// 取大顶堆的堆顶元素(最大值)shuchu
num = max[0];
pop_heap(max.begin(), max.end(), less<int>()); //删除堆顶元素后排序
max.pop_back();
}
min.push_back(num);
push_heap(min.begin(), min.end(), greater<int>());
}
else // 若当前元素个数为奇数,将值插入大顶堆中
{
if (min.size() > 0 && num > min[0])
{
min.push_back(num);
push_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);
push_heap(max.begin(), max.end(), less<int>());
}
}
double GetMedian()
{
int size = min.size() + max.size();
if (size == 0)
return 0;
if ((size & 1) == 0)
return (min[0] + max[0]) / 2.0;
else
return min[0];
}
private:
vector<int> min; // 小顶堆
vector<int> max; // 大顶堆
};

判断一个数是否为奇数还是偶数,除了通过求余之外,还有以上代码中出现的& 1将数字与 1,得到的结果为 0则说明是偶数。

原理:因为偶数的二进制表示,末尾都是以0结束。因此偶数的二进制形式 & 1 之后的结果一定为 0.

注意:这种方法,只适合用在判断奇偶方面,其他用途不适用。

push_hape(_RAIter,_RAIter,_Compare)向堆中插入一个元素,并使堆的规则依然成立。其中_Compare中有两种,less<>()表示大顶堆;另一种是greater<>()表示大顶堆;默认是大顶堆。

pop_heap(_RAIter,_RAIter,_Compare)弹出堆顶元素。参数同上。通常配合.pop_back()删除堆顶元素。


参考博文链接:https://cuijiahua.com/blog/2018/02/basis_63.html

文章作者:zerofly

发布时间:2020年06月08日 - 21:06

原始链接:http://zeroflycui.github.io/9c13d778.html

许可协议: 转载请保留原文链接及作者。