【Java】 劍指offer(41) 數據流中的中位數


本文參考自《劍指offer》一書,代碼采用Java語言。

更多:《劍指Offer》Java實現合集  

題目 

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

思路

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

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

  因此,插入的步驟如下:

  1.若已讀取的個數為偶數(包括0)時,兩個堆的數目已經相同,將新讀取的數插入到小頂堆中,從而實現小頂堆的個數多一。但是,如果新讀取的數字比大頂堆中最大的數字還小,就不能直接插入到小頂堆中了 ,此時必須將新數字插入到大頂堆中,而將大頂堆中的最大數字插入到小頂堆中,從而實現小頂堆的個數多一。

  2若已讀取的個數為奇數時,小頂堆的個數多一,所以要將新讀取數字插入到大頂堆中,此時方法與上面類似。

 

測試算例 

  1.功能測試(讀入奇/偶數個數字)

  2.邊界值測試(讀入0個、1個、2個數字)

Java代碼

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

import java.util.PriorityQueue;
import java.util.Comparator;

public class StreamMedian {
    PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(); //小頂堆,默認容量為11
    PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(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;
    }
}

  

收獲

  1.最大最小堆可以用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的常用方法有:poll(),offer(Object),size(),peek()等。

  2.平均值應該定義為double,且(a+b)/2.0 。

  3.往最大堆中插入數據時間復雜度是O(logn),獲取最大數的時間復雜度是O(1)。

  4.這道題關鍵在於分成兩個平均分配的部分,奇偶時分別插入到最大最小堆中,利用最大最小堆性質的插入方法要掌握。

 

更多:《劍指Offer》Java實現合集  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM