劍指Offer對答如流系列 - 數據流中的中位數

面試題41:數據流中的中位數

一、題目描述

如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。

所謂數據流,就是不會一次性讀入所有數據,只能一個一個讀取,每一步都要求能計算中位數。

二、問題分析

相信上一道題 最小的k個數 給了你容器的啓示。

我們將讀入的數據分爲兩部分,一部分數字小,另一部分大。

小的一部分採用大頂堆存放,大的一部分採用小頂堆存放。當總個數爲偶數時,使兩個堆的數目相同,則中位數=大頂堆的最大數字與小頂堆的最小數字的平均值;而總個數爲奇數時,使小頂堆的個數比大頂堆多一,則中位數=小頂堆的最小數字。

關於插入,我們需要好好思量思量:

  1. 假如已讀取的個數爲偶數(包括0)時,兩個堆的數目已經相同,一般將新讀取的數插入到小頂堆中,從而實現小頂堆的個數多一。但是,如果新讀取的數字比大頂堆中最大的數字還小,要將新數字插入到大頂堆中,並且將大頂堆中的最大數字插入到小頂堆中,從而實現小頂堆的個數多一。
  2. 若已讀取的個數爲奇數時,小頂堆的個數多一,一般要將新讀取數字插入到大頂堆中,但是的處理方法與上面類似。

拓展一下:最大最小堆可以用PriorityQueue實現,PriorityQueue默認是一個小頂堆,通過傳入自定義的Comparator函數可以實現大頂堆:

PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11,new Comparator<Integer>(){ //大頂堆,容量11
    @Override
    public int compare(Integer i1,Integer i2){
        return i2-i1; //降序排列
    }
});

PriorityQueue是JDK內置的,想多點了解可以參考【JDK源碼剖析】Queue–隊列 PriorityQueue–優先隊列

三、問題解答

 	PriorityQueue<Integer> minHeap = new PriorityQueue<>(); //小頂堆,默認容量爲11
    PriorityQueue<Integer> maxHeap = new PriorityQueue<>(11,new Comparator<Integer>(){ //大頂堆,容量11
        public int compare(Integer i1,Integer i2){
            return i2-i1;
        }
    });

    public void Insert(Integer num) {
        if(((minHeap.size()+maxHeap.size())&1 )==0){
            //偶數時,下個數字加入小頂堆
            if(!maxHeap.isEmpty() && maxHeap.peek() > num){
                maxHeap.offer(num);
                num=maxHeap.poll();
            }
            minHeap.offer(num);
        } else {
            //奇數時,下一個數字放入大頂堆
            if(!minHeap.isEmpty() && minHeap.peek() < num){
                minHeap.offer(num);
                num=minHeap.poll();
            }
            maxHeap.offer(num);
        }
    }

    // 獲取以有的數據的中位數
    public Double GetMedian() {
        if((minHeap.size()+maxHeap.size())==0) {
            throw new RuntimeException();
        }
        double median;
        if((minHeap.size()+maxHeap.size()&1)==0){
            median=(maxHeap.peek()+minHeap.peek())/2.0;
        }else{
            median=minHeap.peek();
        }
        return median;
    }
發佈了194 篇原創文章 · 獲贊 3472 · 訪問量 53萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章