数据流中的中位数

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

 

分析:

中位数就是数据排序前一部分的最后一个(最大值)和后半部分的第一个(最小值)的平均。当元素个数为奇数个时可以看成这两个数一样

题目并没有给定一定元素的数组,让求中位数,这样就很简单了,直接排序取中间。题目是说一个数据流,每次会读入一个元素,每读入一个元素后都可以输出中位数。如果还是用刚才的方法,就是用一个list存,每读入一个就进行一次排序,这样很烦。。


这里使用两个堆,一个大根堆,保存前半部分数据,小根堆保存后半部分数据。小根堆数据大于大根堆
为了实现平均分配,可以在当前数据的总数目是偶数时把新数据插入到最小堆中(此时总数+1),否则插入最大堆中。这样也保证了两个堆的数目相差不超过1
最后的结果就是:如果总数是偶数个时,就是小根堆的最小值和大根堆的最大值的平均。
如果是奇数个时,因为添加最后一个元素之前是偶数个,所以会将最后一个添加到小根堆中,所以返回小根堆最小值。

注意:在新插入一个数据时,假设之前总数是偶数,根据自定义规则,这时会将新元素加入到小根堆中,但是此时不能保证此元素会比大根堆的数据大。
所以此时加入小根堆的是新元素和大根堆所有元素的最大值(先加入大根堆,再取出大根堆中最大值加入到小根堆),而不是新元素
同理,如果当前总数是奇数,就会将新元素和小根堆所有元素的最小值加入大根堆。

public class Solution {
    /*
    java中默认的堆是小根堆,要实现大根堆可以自己设置比较方式
    */
    int count=0;
    PriorityQueue<Integer> minQue=new PriorityQueue<>();
    PriorityQueue<Integer> maxQue=new PriorityQueue<Integer>(11,new Comparator<Integer>(){
        public int compare(Integer o1,Integer o2){
            return o2-o1;
        }
    });
    public void Insert(Integer num) {
        /*
            当当前数据总数为偶数时,将新元素和大根堆所有元素的最大值加入小根堆。
            当当前数据总数为奇数时,将新元素和小根堆所有元素的最小值加入大根堆。
        */
        if(count%2==0){
            
                maxQue.offer(num);
                minQue.offer(maxQue.poll());
                
            
        }else{
            minQue.offer(num);
            maxQue.offer(minQue.poll());
        }
        count++;
    }

    public Double GetMedian() {
       if(count%2==0){
           return new Double((minQue.peek()+maxQue.peek()))/2;
       }else
           return new Double(minQue.peek());
    }


}

 

posted on 2018-01-17 14:52  夜的第八章  阅读(266)  评论(2编辑  收藏  举报

导航