1.题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
2.算法描述
什么是堆?
堆就是用数组实现的一颗完全二叉树,最大堆的根元素值最大,并且左右子树也是最大堆;同理最小堆的定义类似。
堆的定义
方法
用
两
个
堆
来
实
现
,
就
不
用
每
次
来
一
个
元
素
都
要
排
序
。
\red{用两个堆来实现,就不用每次来一个元素都要排序。}
用两个堆来实现,就不用每次来一个元素都要排序。
初
始
化
两
个
堆
,
m
i
n
H
e
a
p
,
m
a
x
H
e
a
p
分
别
为
最
小
堆
和
最
大
堆
。
\red{初始化两个堆,minHeap,maxHeap分别为最小堆和最大堆。}
初始化两个堆,minHeap,maxHeap分别为最小堆和最大堆。
插
入
元
素
操
作
:
当
一
个
元
素
进
入
数
据
流
时
,
\red{插入元素操作:当一个元素进入数据流时,}
插入元素操作:当一个元素进入数据流时,
若
数
据
流
中
已
有
奇
数
个
元
素
,
则
该
元
素
先
进
入
到
最
小
堆
中
,
然
后
将
最
小
堆
的
根
元
素
弹
出
并
进
入
到
最
大
堆
中
;
\red{\ \ \ \ 若数据流中已有奇数个元素,则该元素先进入到最小堆中,然后将最小堆的根元素弹出并进入到最大堆中;}
若数据流中已有奇数个元素,则该元素先进入到最小堆中,然后将最小堆的根元素弹出并进入到最大堆中;
若
数
据
流
中
已
有
偶
数
个
元
素
,
则
该
元
素
先
进
入
到
最
大
堆
中
,
然
后
将
最
大
堆
的
根
元
素
弹
出
并
进
入
到
最
小
堆
中
。
\red{\ \ \ \ 若数据流中已有偶数个元素,则该元素先进入到最大堆中,然后将最大堆的根元素弹出并进入到最小堆中。}
若数据流中已有偶数个元素,则该元素先进入到最大堆中,然后将最大堆的根元素弹出并进入到最小堆中。
经过上述操作之后:
最小堆中装的是整个数据流从小到大的后一半元素(如果是奇数个元素,则还要多一个),
最大堆中装的是整个数据流从小到大的前一半元素。
返
回
中
位
数
操
作
:
\red{返回中位数操作:}
返回中位数操作:
若
数
据
流
中
的
元
素
是
奇
数
个
元
素
,
则
返
回
最
小
堆
的
根
元
素
;
\red{\ \ \ \ 若数据流中的元素是奇数个元素,则返回最小堆的根元素;}
若数据流中的元素是奇数个元素,则返回最小堆的根元素;
否
则
,
则
返
回
最
小
堆
的
根
元
素
和
最
大
堆
根
元
素
的
平
均
值
。
\red{\ \ \ \ 否则,则返回最小堆的根元素和最大堆根元素的平均值。}
否则,则返回最小堆的根元素和最大堆根元素的平均值。
3.代码描述
3.1.Java代码
import java.util.*;
public class Solution {
private int count = 0;
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1,o2)->o2-o1);
public void Insert(Integer num) {
if(count % 2 == 0){
//当数据总数为偶数时,新加入的元素,应当进入小根堆
//不是直接进入小根堆,而是经大根堆筛选后取大根堆中最大元素进入小根堆
//新加入的元素先入到大根堆,由大根堆筛选出堆中最大的元素
maxHeap.offer(num);
int elem = maxHeap.poll();
minHeap.offer(elem);
}
else{
//当数据总数为奇数时,新加入的元素,应当进入大根堆
//注意不是直接进入大根堆,而是经小根堆筛选后取小根堆中最大元素进入大根堆
//新加入的元素先入到小根堆,由小根堆筛选出堆中最小的元素
minHeap.offer(num);
int elem = minHeap.poll();
maxHeap.offer(elem);
}
count++;
}
public Double GetMedian() {
if(count % 2 == 0){//如果是偶数个数 就把小顶堆的根元素和大顶堆的根元素 拿出
return (minHeap.peek() + maxHeap.peek())/2.0;
}
else{//如果是奇数个数 那说明中位数就在小顶堆的根的位置
return minHeap.peek()/1.0;
}
}
}
3.2.Python代码
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.data = []
def Insert(self, num):
self.data.append(num)
self.data.sort()
def GetMedian(self,data):
length=len(self.data)
if length%2==0:
return (self.data[length//2]+self.data[length//2-1])/2.0
else:
return self.data[int(length//2)]