1. 程式人生 > >劍指offer:資料流中的中位數(java)

劍指offer:資料流中的中位數(java)

/**
 * 題目:
 *      如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,
 *      那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,
 *      那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取資料流,
 *      使用GetMedian()方法獲取當前讀取資料的中位數。
 * 解題思路:
 *      用兩個推儲存資料,保持兩個堆的資料保持平衡(元素個數相差不超過1)
 *      大頂堆存放的資料要比小頂堆的資料小
 *      當兩個推中元素為偶數個,將新加入元素加入到大頂堆,如果要加入的資料,比小頂堆的最小元素大,
 *      先將該元素插入小頂堆,然後將小頂堆的最小元素插入到大頂堆。
 *      當兩個推中元素為奇數個,將新加入元素加入到小頂堆,如果要加入的資料,比大頂堆的最大元素小,
 *      先將該元素插入大頂堆,然後將大頂堆的最大元素插入到小頂堆。
 *      當元素個數是奇數個時,大頂堆元素比小頂堆多一個,中位數即為大頂堆的堆頂元素
 *      若為偶數,則中位數是大小頂堆的堆頂元素之和除2
 */
import java.util.TreeSet;
public class P214_GetMedian {
    TreeSet<Integer> max = new TreeSet<Integer>();  //大頂堆,用於存放前面一半的元素
    TreeSet<Integer> min = new TreeSet<Integer>();  //小頂堆,用於存放後面一般的元素
    public void Insert(Integer num) {
        if (((max.size()+min.size()) & 1) == 0) { //偶數個
            if (min.size() > 0 && num > min.first()) {
                min.add(num);
                num = min.first();
                min.remove(num);
            }
            max.add(num);
        }else {
            if (max.size() > 0 && num < max.last()) {
                max.add(num);
                num = max.last();
                max.remove(num);
            }
            min.add(num);
        }
    }

    public Double GetMedian() {
        int size = max.size() + min.size();
        if (size == 0) {
            return 0.0;
        }
        if ((size & 1) == 0) {
            return (max.last() + min.first()) / 2.0;
        }else {
            return (double)max.last();
        }
    }
}