1. 程式人生 > >【原理思路】大資料中找中位數(騰訊面試題)

【原理思路】大資料中找中位數(騰訊面試題)

題目:

在一個大檔案中有100億個32位整數,亂序排列,要求找出中位數;記憶體限制為512M;請寫出演算法設計思路;

基本分析:

(1)中位數的定義:一個給定排序好的序列,奇數個的話,我們就取中間的一個;偶數個的話,我們一般取中間兩個數的平均值;因此對於本題,我們需得到中間的第50億和第50億+1這兩個數;

(2)首先512M的記憶體,如果都來裝這個32位整數的話,可以儲存2^(9+10+10)/4=2^27(134217728)個數(1億左右的數);常規的內部排序肯定是不行了,因為記憶體不夠;而且是亂序排列,所以二分查詢不行;所以本題的時間複雜度最少為O(n);

(3)由於記憶體是512M,可儲存1億個數;那麼我們先把100億個數分成100組;

使用512M高記憶體可裝載1億個數,裝載100次;

演算法思路:

(1)我們要劃分對映區域,一個有符號的32位整數的取值範圍是[-2^31, 2^31-1],總共有4294967296個取值,因此我們將它劃分成100000組,即43000個數對映到一個組,將a1的區間[-2^31,-2^31+43000),a2的區間[-2^31+43000-2^31+86000)......一直到a100000的區間;(這是組數與項數的一個平衡問題);

(2.1)我們首先裝載第一個1億個數,遍歷這些數,比較大小,看他落入a1至a100000的哪個區間,落入的對應區間統計計數增1;這次是對這裡面的數區間的組對映;

(2.2)重複步驟(2.1),裝載100次,這樣我們就得到了a1至a100000的區間統計計數的取值;

(2.3)記憶體分析:1億個數用來裝載,100000個區間統計計數耗費400000個位元組,足夠使用;剩餘記憶體(128M-1億-100000)*4B;

(3.1)使用sum依次累加a1至a100000的區間統計計數,直到累加某區間ai後sum大於50億了;那麼第50億個數就在該區間中,用sum減去該區間ai的統計數的到first;即前面的區間統計總數位置為第first個(其中first < 50億);

(3.2)那麼我就在ai區間找到第50億-first個數,或第50億-first+1個數(第50億-first+1個數這個數可能在ai後面的區間,但是概率很小,但是找到的原理類似);

(3.3)記憶體分析:每一個區間分割比較要花費100000個區間比較數,耗費400000個位元組,足夠使用;剩餘記憶體(128M-1億-100000-100000-2

)*4B;

(4.1)再次遍歷這100億個數,還是每組1億個數,一共100組;對於若在ai區間的43000個數的每一個都開一個統計計數器 ,跟上面類似,這次是對這裡面的數單個對映;

(4.2)同樣使用sum依次累加這1至43000的的統計計數,直到累加某區間後sum大於50億-first;那麼我們可以得到第(50億-first)個數就在對應的位置;而且第(50億-first+1)個數位置也有可能在,或在下一個統計計數大於0的位置;當然也有可能不在ai區間;(但原理類似);

(4.3)得到了第(50億-first)個數值;而且第(50億-first+1)個數值,可算出中位數了;

(4.4)記憶體分析:上述的100000個比較數,此時我們只需要兩個比較數;100000個區間統計計數全部釋放掉,但增加了43000位置統計計數;剩餘記憶體(128M-1億-43000-2-2)*4B;還是足夠使用的;

(5)總共遍歷兩遍100億資料;