题目
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序后中间两个数的平均值。
解题思路
用一个最大堆实现左边的数据容器,用一个最小堆实现右边的数据容器。往队中插入一个数据的时间效率为O(logn)。由于只要O(1)时间就可以得到位于堆顶的数据,因此得到中位数的时间复杂度是O(1)。
源代码
package Arithmetic;
import java.util.PriorityQueue;
import java.util.Scanner;
public class MedianData {
/*大顶堆,存储左半边元素*/
private PriorityQueue<Integer> left = new PriorityQueue<>((o1, o2) -> o2 - o1);
/*小顶堆,存储右半边元素,并且右半边元素都会大于左半边*/
private PriorityQueue<Integer> right = new PriorityQueue<>();
/*记录当前数据流读入的元素个数*/
private int N = 0;
public void Insert(Integer val) {
/*插入要保证两个堆处于平衡状态*/
if (N % 2 == 0) {
/*
* N为偶数的情况下插入到右边
* 因为右半边元素都大于左半边,但是新插入的元素不一定比左半边元素都大
* 因此需要先将元素插入左半边,然后利用左半边为大顶堆的特点,取出堆顶元素为最大元素,此时插入右半边
* */
left.add(val);
right.add(left.poll());
} else {
right.add(val);
left.add(right.poll());
}
N++;
}
//返回中位数
public Double GetMedian() {
if (N % 2 == 0)
return (left.peek() + right.peek()) / 2.0;
else
return (double) right.peek();
}
public static void main(String[] args) {
MedianData medianData = new MedianData();
Scanner scanner = new Scanner(System.in);
int total = scanner.nextInt();
for (int i = 1; i <= total; i++) {
int num = (int) (Math.random() * 100);
System.out.print(num + " ");
medianData.Insert(num);//插入数据
}
System.out.println();
System.out.println(medianData.GetMedian());//输出中位数
}
}