剑指笔记——41 数据流中的中位数

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

思路:这个题好复杂。。。。

创建优先级队列维护大顶堆和小顶堆两个堆,并且小顶堆的值都大于大顶堆的值,2个堆个数的差值小
于等于1,所以当插入个数为奇数时:大顶堆个数就比小顶堆多1,中位数就是大顶堆堆头;当插入个数为偶数
时,使大顶堆个数跟小顶堆个数一样,中位数就是 2个堆堆头平均数。也可使用集合类的排序方法

要保证最大堆中的数字都小于最小堆中的数字。可以把新的数据放入最大堆,接着把最大堆中的最大的数字拿出那插入最小堆,这样就保证了最小堆中的所有数据都大于最大堆的数据。

在这里还涉及到优先队列的部分,这部分我有点忘了,把一些点补充在这里:

 优先级队列从队列中取出的是具有最高优先权的元素。PriorityQueue是从JDK1.5开始提供的新的数据结构接口。

如果不提供Comparator的话,优先队列中元素默认按自然顺序排列,也就是数字默认是小的在队列头(从小到大),字符串则按字典序排列

对于这种解法,插入的时间复杂度是O(logn),得到中位数的时间复杂度是O(1).

代码:

int count = 0;
PriorityQueue<Integer> minHeap = new PriorityQueue<>();  //这个优先队列的顺序使从小到大
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(16, new Comparator<Integer>() {
@Override                                                        //这个是匿名类,重写了compare方法,注意返回值的写法,这里这样写就是使得
public int compare(Integer o1, Integer o2) {       //优先队列的排序是从大到小
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());  //这块返回的是Double的数据类型,注意要改变下类型
} else {
return Double.valueOf((minHeap.peek() + maxHeap.peek())) / 2;
}
}

猜你喜欢

转载自blog.csdn.net/chenxy132/article/details/89340651