如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。
思路:可以建立一個大堆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());
}
}
}