/*
* 面试题41:数据流中的中位数
* 题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。
* 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
* 我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
* 思路:创建优先级队列维护大顶堆和小顶堆两个堆,并且小顶堆的值都大于大顶堆的值,2个堆个数的差值小于等于1,
* 所以当插入个数为奇数时:大顶堆个数就比小顶堆多1,中位数就是大顶堆堆头;
* 当插入个数为偶数时,使大顶堆个数跟小顶堆个数一样,中位数就是 2个堆堆头平均数。也可使用集合类的排序方法。
*
* Java的PriorityQueue 是从JDK1.5开始提供的新的数据结构接口,默认内部是自然排序,结果为小顶堆,也可以自定义排序器,比如下面反转比较,完成大顶堆。
*/
import java.util.Comparator;
import java.util.PriorityQueue;
public class No41GetMedian {
public static void main (String[] args) {
No41GetMedian n = new No41GetMedian();
n.Insert(1);
n.Insert(2);
n.Insert(3);
n.Insert(4);
System.out.print(n.GetMedian());
}
int count;
PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// PriorityQueue默认是小顶堆,实现大顶堆,需要反转默认排序器
return o2.compareTo(o1);
}
});
public void Insert(Integer num) {
count++;
// 当数据的个数为奇数时,进入大根堆
if ((count & 1) == 1) {
minHeap.offer(num);
maxHeap.offer(minHeap.poll());
} else {
maxHeap.offer(num);
minHeap.offer(maxHeap.poll());
}
}
public Double GetMedian() {
if (count == 0) {
return null;
}
// 当数据个数是奇数时,中位数就是大根堆的顶点
if ((count & 1) == 1) {
return Double.valueOf(maxHeap.peek());
} else {
return Double.valueOf((minHeap.peek() + maxHeap.peek())) / 2;
}
}
}
面试题41:数据流中的中位数
最新推荐文章于 2020-05-08 10:42:50 发布