1. 程式人生 > >劍指offer____資料流中的中位數

劍指offer____資料流中的中位數

如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取資料流,使用GetMedian()方法獲取當前讀取資料的中位數。

/*
如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。
 
對於資料流,對應的就是線上演算法了,一道很經典的題目就是在1億個數中找到最大的前100個數,這是一道堆應用題,找最大的前100個數,那麼我們就建立一個大小為100的最小化堆,每來一個元素就與堆頂元素比較,因為堆頂元素是目前前100大數中的最小數,前來的元素如果比該元素大,那麼就把原來的堆頂替換掉。
那麼對於這一道題呢?如果單純的把所有元素放到一個數組裡,每次查詢中位數最快也要O(n),綜合下來是O(n^2)的複雜度。我們可以利用上面例子中的想法,用一個最大堆來維護當前前n/2小的元素,那麼每次找中位數只到取出堆頂就可以了。但是,有一個問題,資料要動態增長,有可能之前被替換掉的元素隨著元素的增加又跑回來了,所以我們不能單純得向上題一樣把元素丟掉,我們可以再用一個最小化堆來存前n/2大的元素。
*/
class Solution {
 private:
        vector<int> min; //陣列中的後一半元素組成一個最小化堆
        vector<int> max; //陣列中的前一半元素組成一個最大化堆
public:
       void Insert(int num)
       {
             if(((min.size()+max.size()) & 1) == 0) 
             {  //偶數資料的情況下,則在最小堆中插入元素
                 if(max.size() > 0 && num < max[0]) 
                 {
                     max.push_back(num);
                     push_heap(max.begin(), max.end(), less<int>());
                     num=max[0];
                     pop_heap(max.begin(), max.end(), less<int>());
                     max.pop_back();
                 }
                 min.push_back(num); //把前一半找到的最大值放到後一半中
                 push_heap(min.begin(), min.end(), greater<int>());
             } else 
             {
                 if(min.size() > 0 && num > min[0]) 
                 {   //奇數資料的情況下,則在最大堆中插入元素
                     min.push_back(num);
                     push_heap(min.begin(), min.end(), greater<int>());                     num=min[0];
                     pop_heap(min.begin(), min.end(), greater<int>());
                     min.pop_back(); 
                 }
                 max.push_back(num); //把後一半找到的最大值放到前一半中
                 push_heap(max.begin(), max.end(), less<int>());
            }
         }
 
         double GetMedian() 
         { 
             int size=min.size() + max.size();
             if(size==0) return -1;
             double median = 0;
             if((size&1) != 0) 
             {
                 median = (double) min[0];
             } 
             else 
             {
                 median = (double) (max[0] + min[0]) / 2;
             }
             return median;
           }

};