題目:在乙個檔案中有 10g 個整數,亂序排列,要求找出中位數。記憶體限制為 2g。只寫出思路即可(記憶體限制為 2g的意思就是,可以使用2g的空間來執行程式,而不考慮這台機器上的其他軟體的占用記憶體)。
關於中位數:資料排序後,位置在最中間的數值。即將資料分成兩部分,一部分大於該數值,一部分小於該數值。中位數的位置:當樣本數為奇數時,中位數=(n+1)/2 ; 當樣本數為偶數時,中位數為n/2與1+n/2的均值(那麼10g個數的中位數,就第5g大的數與第5g+1大的數的均值了)。
分析:明顯是一道工程性很強的題目,和一般的查詢中位數的題目有幾點不同。
1. 原資料不能讀進記憶體,不然可以用快速選擇,如果數的範圍合適的話還可以考慮桶排序或者計數排序,但這裡假設是32位整數,仍有4g種取值,需要乙個16g大小的陣列來計數。
2. 若看成從n個數中找出第k大的數,如果k個數可以讀進記憶體,可以利用最小或最大堆,但這裡k=n/2,有5g個數,仍然不能讀進記憶體。
3. 接上,對於n個數和k個數都不能一次讀進記憶體的情況,《程式設計之美》裡給出乙個方案:設k解法:首先假設是32位無符號整數。
1. 讀一遍10g個整數,把整數對映到256m個區段中,用乙個64位無符號整數給每個相應區段記數。
說明:整數範圍是0 - 2^32 - 1,一共有4g種取值,對映到256m個區段,則每個區段有16(4g/256m = 16)種值,每16個值算一段, 0~15是第1段,16~31是第2段,……2^32-16 ~2^32-1是第256m段。乙個64位無符號整數最大值是0~8g-1,這裡先不考慮溢位的情況。總共占用記憶體256m×8b=2gb。
2. 從前到後對每一段的計數累加,當累加的和超過5g時停止,找出這個區段(即累加停止時達到的區段,也是中位數所在的區段)的數值範圍,設為[a,a+15],同時記錄累加到前乙個區段的總數,設為m。然後,釋放除這個區段占用的記憶體。
3. 再讀一遍10g個整數,把在[a,a+15]內的每個值計數,即有16個計數。
4. 對新的計數依次累加,每次的和設為n,當m+n的值超過5g時停止,此時的這個計數所對應的數就是中位數。
總結:1.以上方法只要讀兩遍整數,對每個整數也只是常數時間的操作,總體來說是線性時間。
2. 考慮其他情況。
若是有符號的整數,只需改變對映即可。若是64為整數,則增加每個區段的範圍,那麼在第二次讀數時,要考慮更多的計數。若過某個計數溢位,那麼可認定所在的區段或代表整數為所求,這裡只需做好相應的處理。噢,忘了還要找第5g+1大的數了,相信有了以上的成果,找到這個數也不難了吧。
3. 時空權衡。
花費256個區段也許只是恰好配合2gb的記憶體(其實也不是,呵呵)。可以增大區段範圍,減少區段數目,節省一些記憶體,雖然增加第二部分的對單個數值的計數,但第一部分對每個區段的計數加快了(總體改變??待測)。
4. 對映時盡量用位操作,由於每個區段的起點都是2的整數冪,對映起來也很方便。
10G整數檔案中尋找中位數
from 題目 在乙個檔案中有 10g 個整數,亂序排列,要求找出中位數。記憶體限制為 2g。只寫出思路即可 記憶體限制為 2g的意思就是,可以使用2g的空間來執行程式,而不考慮這台機器上的其他軟體的占用記憶體 關於中位數 資料排序後,位置在最中間的數值。即將資料分成兩部分,一部分大於該數值,一部分...
從10G個數中找到中數
在乙個檔案中有 10g 個整數,亂序排列,要求找出中位數。記憶體限制為 2g。不妨假設10g個整數是64bit的。2g記憶體可以存放256m個64bit整數。我們可以將64bit的整數空間平均分成256m個取值範圍,用2g的記憶體對每個取值範圍內出現整數個數進行統計。這樣遍歷一邊10g整數後,我們便...
問題 G 中位數
中位數定義 一組資料按從小到大的順序依次排列,處在中間位置的乙個數 或最中間兩個資料的平均數 給出一組無序整數,求出中位數,如果求最中間兩個數的平均數,向下取整即可 不需要使用浮點數 輸入 該程式包含多組測試資料,每一組測試資料的第一行為n,代表該組測試資料報含的資料個數,1 n 10000.接著n...