如今 有10億個int型的數字(JAVA中 int 型佔4B),以及一臺可用內存爲1GB的機器,如何找出這10億個數字的中位數?html
中位數定義:數字排序以後,位於中間的那個數。好比將10億個數字進行排序(位置從1到10億),排序以後,位於第5億個位置的那個數 就是中位數。算法
關於中位數,可參考:快速排序中的分割算法的解析與應用數組
一種方法是定義一個長度爲10億的整型數組,採用排序算法排序。可是:post
10億個數字,每一個數字在內存中佔4B,10億個數字徹底加載到內存中須要:10*108*4B ,約爲:4GB內存。顯然不能把全部的數字都裝入內存。url
這裏,採用基於二進制位比較 和 快速排序算法中的「分割思想」來尋找中位數。具體以下:spa
假設10億個數字保存在一個大文件中,依次讀一部分文件到內存(不超過內存的限制:1GB),將每一個數字用二進制表示,比較二進制的最高位(第32位),若是數字的最高位爲0,則將這個數字寫入 file_0文件中;若是最高位爲 1,則將該數字寫入file_1文件中。【這裏的最高位相似於快速排序中的樞軸元素】設計
從而將10億個數字分紅了兩個文件(幾乎是二分的),假設 file_0文件中有 6億 個數字,file_1文件中有 4億 個數字。那麼中位數就在 file_0 文件中,而且是 file_0 文件中全部數字排序以後的第 1億 個數字。htm
【爲何呢?由於10億個數字的中位數是10億個數排序以後的第5億個數。如今file_0有6億個數,file_1有4億個數,file_0中的數都比file_1中的數要大(最高位爲符號位,file_1中的數都是負數,file_0中的數都是正數,也即這裏一共只有4億個負數,排序以後的第5億個數必定是正數,那麼排序以後的第5億個數必定位於file_0中)】。除去4億個負數,中位數就是6億個正數從小到大排序以後 的第 1 億個數。blog
如今,咱們只須要處理 file_0 文件了(不須要再考慮file_1文件)。對於 file_0 文件,一樣採起上面的措施處理:將file_0文件依次讀一部分到內存(不超內存限制:1GB),將每一個數字用二進制表示,比較二進制的 次高位(第31位),若是數字的次高位爲0,寫入file_0_0文件中;若是次高位爲1,寫入file_0_1文件 中。排序
現假設 file_0_0文件中有3億個數字,file_0_1中也有3億個數字,則中位數就是:file_0_0文件中的數字從小到大排序以後的第1億個數字。
拋棄file_0_1文件,繼續對 file_0_0文件 根據 次次高位(第30位) 劃分,假設這次劃分的兩個文件爲:file_0_0_0中有0.5億個數字,file_0_0_1中有2.5億個數字,那麼中位數就是 file_0_0_1文件中的全部數字排序以後的 第 0.5億 個數。
......
按照上述思路,直到劃分的文件可直接加載進內存時(好比劃分的文件中只有5KW個數字了),就能夠直接對數字進行快速排序,找出中位數了。固然,你也使用「快排的分割算法」來找出中位數(比使用快速排序要快)
總結:上面的海量數據尋找中位數,其實就是利用了「分割」思想,每次將 問題空間 大約分解成原問題空間的一半左右。(劃分紅兩個文件,直接丟棄其中一個文件),故總的複雜度可視爲O(logN) N=10億。
參考資料:
原文:http://www.cnblogs.com/hapjin/p/5769087.html