參考 https://blog.csdn.net/u011080472/article/details/51291089html
題目描述java
如何獲得一個數據流中的中位數?若是從數據流中讀出奇數個數值,那麼中位數就是全部數值排序以後位於中間的數值。若是從數據流中讀出偶數個數值,那麼中位數就是全部數值排序以後中間兩個數的平均值。數據結構
分析ide
獲取中位數有多種方法,可是各類方法的時間效率不一。下面是多種方法的時間複雜度的比較:有圖能夠知道使用AVL二叉平衡樹的方法和使用最大堆最小堆的方法是總的時間複雜度最優的。可是AVL二叉平衡樹沒有現成的數據結構的實現,所以能夠考慮java集合中的PriorityQueue優先隊列(也就是堆,默認爲小根堆)來實現比較高校的中位數查找。spa
有關優先隊列PriorityQueue,請參考http://www.javashuo.com/article/p-maxuxljr-hr.html.net
思路:考慮將數據序列從中間開始分爲兩個部分,左邊部分使用大根堆表示,右邊部分使用小根堆存儲。每遍歷一個數據,計數器count增長1,當count是偶數時,將數據插入小根堆;當count是奇數時,將數據插入大根堆。當全部數據遍歷插入完成後(時間複雜度爲O(log3d
,若是count最後爲偶數,則中位數爲大根堆堆頂元素和小根堆堆頂元素和的一半;若是count最後爲奇數,則中位數爲小根堆堆頂元素。code
牛客AC:xml
import java.util.PriorityQueue; import java.util.Comparator; public class Solution { private int count = 0; // 數據流中的數據個數 // 優先隊列集合實現了堆,默認實現的小根堆 private PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // 定義大根堆,更改比較方式 private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(15, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; // o1 - o2 則是小根堆 } }); public void Insert(Integer num) { if ((count & 1) == 0) { // 當數據總數爲偶數時,新加入的元素,應當進入小根堆 // (注意不是直接進入小根堆,而是經大根堆篩選後取大根堆中最大元素進入小根堆) // 1.新加入的元素先入到大根堆,由大根堆篩選出堆中最大的元素 maxHeap.offer(num); int filteredMaxNum = maxHeap.poll(); // 2.篩選後的【大根堆中的最大元素】進入小根堆 minHeap.offer(filteredMaxNum); } else { // 當數據總數爲奇數時,新加入的元素,應當進入大根堆 // (注意不是直接進入大根堆,而是經小根堆篩選後取小根堆中最大元素進入大根堆) // 1.新加入的元素先入到小根堆,由小根堆篩選出堆中最小的元素 minHeap.offer(num); int filteredMinNum = minHeap.poll(); // 2.篩選後的【小根堆中的最小元素】進入小根堆 maxHeap.offer(filteredMinNum); } count++; } public Double GetMedian() { // 數目爲偶數時,中位數爲小根堆堆頂元素與大根堆堆頂元素和的一半 if ((count & 1) == 0) { return new Double((minHeap.peek() + maxHeap.peek())) / 2; } else { return new Double(minHeap.peek()); } } }