題目:在乙個檔案中有 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 個整數,亂序排列,要求找出中位數。記憶體限制為 2g。只寫出思路即可 記憶體限制為 2g的意思就是,可以使用2g的空間來執行程式,而不考慮這台機器上的其他軟體的占用記憶體 關於中位數 資料排序後,位置在最中間的數值。即將資料分成兩部分,一部分大於該數值,一部分小於該數值...
海量資料找中位數
題目如下 只有2g記憶體的pc機,在乙個存有10g個整數的檔案,從中找到中位數,寫乙個演算法。給出了四種方法來解決 演算法 1.利用外排序的方法,進行排序 然後再去找中位數 2.另外還有個思路利用堆 先求第1g大,然後利用該元素求第2g大,然後利用第2g大,求第3g大.當然這樣的話雖不需排序,但是磁...
海量資料求中位數
參考 1.最簡單 排序 2.堆 4g資料,1g記憶體 步驟 先將1g記憶體都塞進乙個大頂堆,然後小於堆頂的數,插入堆,並pop堆頂,一次遍歷後,得到第1g大的數 第二次遍歷,過濾小於第1g大的數,同樣塞滿乙個1g的大頂堆,小於堆頂的插入堆,並pop堆頂,得到第2g大的數字 3.二分 統計 比如數字範...