63 数据流的中位数

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

 

用两个堆保存数据,保持两个堆的数据保持平衡(元素个数相差不超过1)

大顶堆存放的数据要比小顶堆的数据小

当两个堆中元素为奇数个,将新加入元素加入到大顶堆,如果要加入的数据,比小顶堆的最小元素大,先将该元素插入小顶堆,然后将小顶堆的最小元素插入到大顶堆。

当两个堆中元素为偶数个,将新加入元素加入到小顶堆,如果要加入的数据,比大顶堆的最大元素小,先将该元素插入大顶堆,然后将大顶堆的最大元素插入到小顶堆。

 

 1 import java.util.Comparator;
 2 import java.util.PriorityQueue;
 3 public class Solution {
 4     //全局变量count用来统计加入了多少个数
 5     int count=0;
 6     PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
 7     PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11, new Comparator<Integer>() {
 8         @Override
 9         public int compare(Integer o1, Integer o2) {
10             //PriorityQueue默认是小顶堆,实现大顶堆,需要反转默认排序器
11             return o2.compareTo(o1);
12         }
13     });
14     public void Insert(Integer num) {
15     count++;
16           //每次插入小顶堆的是当前大顶堆中最大的数
17           //每次插入大顶堆的是当前小顶堆中最小的数
18           //这样保证小顶堆中的数永远大于等于大顶堆中的数
19           //中位数就可以方便地从两者的根结点中获取了
20     if( (count & 1) == 0) { // 判断偶数的高效写法
21             if (!maxHeap.isEmpty() && num < maxHeap.peek()) {
22                 maxHeap.offer(num);
23                 num = maxHeap.poll();
24             }
25             minHeap.offer(num);
26         } else { //奇数情况
27             if (!minHeap.isEmpty() && num > minHeap.peek()) {
28                 minHeap.offer(num);
29                 num = minHeap.poll();
30             }
31             maxHeap.offer(num);
32         }
33     }
34     public Double GetMedian() {   
35         if(count==0)
36             throw new RuntimeException("no available number!");
37         double result;
38        //总数为奇数时,大顶堆堆顶就是中位数
39        if((count&1)==1)
40             result=maxHeap.peek();
41         else
42             result=(minHeap.peek()+maxHeap.peek())/2.0;
43         return result;
44     }
45 }

 

posted @ 2019-07-25 11:10  淡如水94  阅读(147)  评论(0)    收藏  举报