求數據流中的中位數

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

思路:可以建立一個大堆maxHeap用來保存較小n/2的數,一個小堆minHeap用來保存Math.ceil(n/2)個數。

1.開始時,maxHeap和minHeap都爲空,即大小都爲0,則將第一個數保存到minHeap中。

2.後面的待插入的數,首先比較maxHeap和minHeap的元素個數的大小,相等則應該存儲到小堆minHeap中,否則保存到元素個數小的那個。

3.假設要保存到大堆中,則這個數num應該要比minHeap的堆頂元素小或者相等,假若大於minHeap的堆頂元素,則應將minHeap的堆頂元素與num互換,重建minHeap,並將此時的num插入到大堆maxHeap,重建maxHeap;

4.假設要保存到小堆中,過程與步驟3類似。

5.獲取中位數,若maxHeap和minHeap的元素個數相等,則爲其兩個堆頂元素的平均值,否則爲minHeap堆頂元素的值。


java實現代碼如下:

import java.util.*;
public class MedianNumber {
	public int maxHeapSize=0;
    public int minHeapSize=0;
    public ArrayList<Integer> maxHeap=new ArrayList<Integer>();
    public ArrayList<Integer> minHeap=new ArrayList<Integer>();
    
    // fg=0 表示 大根堆
    public void buildHead(ArrayList<Integer> list,int length,int fg){
        
        for(int i=(length-2)/2;i>=0;i-- ){
            int k=i;
            while(2*k+1<=length-1){
                int bigIndex=2*k+1;
                if(bigIndex<length-1){
                    if(fg==0){
                        if(list.get(bigIndex)<list.get(bigIndex+1)){
                        	bigIndex++;
                    	}
                    }else{
                        if(list.get(bigIndex)>list.get(bigIndex+1)){
                        	bigIndex++;
                    	}
                    }
                    
                }
                if(fg==0){
                    if(list.get(k)<list.get(bigIndex)){
                        int temp1=list.get(k);
                        int temp2=list.get(bigIndex);
                        list.remove(k);
                        list.add(k, temp2);
                        list.remove(bigIndex);
                        list.add(bigIndex, temp1);
                        k=bigIndex;
                    }else{
                        break;
                    }
                }else{
                    if(list.get(k)>list.get(bigIndex)){
                    	 int temp1=list.get(k);
                         int temp2=list.get(bigIndex);
                         list.remove(k);
                         list.add(k, temp2);
                         list.remove(bigIndex);
                         list.add(bigIndex, temp1);
                         k=bigIndex;
                    }else{
                        break;
                    }
                }
                
            }           
        }
    }
    
    public void Insert(Integer num) {
    	if(minHeapSize==0){
    		minHeap.add(num);
    		minHeapSize++;
    		return;
    	}
 	
        if(maxHeapSize<minHeapSize){
        	
        		if(num<=minHeap.get(0)){
        			maxHeap.add(num);
        		}else{
        			maxHeap.add(minHeap.get(0));
        			minHeap.remove(0);
        			minHeap.add(num);
        			buildHead(minHeap,minHeapSize,1);
        		}
        	
            
            buildHead(maxHeap,++maxHeapSize,0);
        }else{
        	if(num<maxHeap.get(0)){
        		
        			minHeap.add(maxHeap.get(0));
        			maxHeap.remove(0);
        			maxHeap.add(num);
        			buildHead(maxHeap,minHeapSize,0);
        	}else{
        		minHeap.add(num);
        	}
            
            buildHead(minHeap,++minHeapSize,1);
        }
    }

    public Double GetMedian() {
        double ans=0;
        if(minHeapSize==maxHeapSize){
            ans=(maxHeap.get(0)+minHeap.get(0))*1.0/2;
        }else{
            ans= minHeap.get(0)*1.0;
        }
        return ans;
    }
    
    public void printHeap(ArrayList<Integer> list){
    	System.out.print("[");
    	for(int i=0;i<list.size();i++){
    		System.out.print(list.get(i)+" ");
    	}
    	System.out.println("]");
    	
    }
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MedianNumber test =new MedianNumber();
		Scanner in=new Scanner(System.in);
		while(in.hasNext()){
			int n=in.nextInt();
			test.Insert(n);
			test.printHeap(test.maxHeap);
			test.printHeap(test.minHeap);
			System.out.println(test.GetMedian());
		}
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章