10G個整數,亂序排列,要求找出中位數。內存限制為 2G。只寫出思路即可


題目:在一個文件中有 10G 個整數,亂序排列,要求找出中位數。內存限制為 2G。只寫出思路即可(內存限制為 2G的意思就是,可以使用2G的    空間來運行程序,而不考慮這台機器上的其他軟件的占用內存)。

 

 

分析: 既然要找中位數,很簡單就是排序的想法。那么基於字節的桶排序是一個可行的方法 (請見《桶排序》):

思想:將整形的每1byte作為一個關鍵字,也就是說一個整形可以拆成4個keys,而且最高位的keys越大,整數越大。

   如果高位keys相同,則比較次高位的keys。整個比較過程類似於字符串的字典序。

第一步:把10G整數每2G讀入一次內存,然后一次遍歷這536,870,912個數據。每個數據用位運算">>"取出最高8位(31-24)。

    這8bits(0-255)最多表示255個桶,那么可以根據8bit的值來確定丟入第幾個桶。

            最后把每個桶寫入一個磁盤文件中,同時在內存中統計每個桶內數據的數量,自然這個數量只需要255個整形空間即可。

代價:(1) 10G數據依次讀入內存的IO代價(這個是無法避免的,CPU不能直接在磁盤上運算)。

   (2)在內存中遍歷536,870,912個數據,這是一個O(n)的線性時間復雜度。

   (3)把255個桶寫會到255個磁盤文件空間中,這個代價是額外的,也就是多付出一倍的10G數據轉移的時間。 

第二步:根據內存中255個桶內的數量,計算中位數在第幾個桶中。很顯然,2,684,354,560個數中位數是第1,342,177,280個。

      假設前127個桶的數據量相加,發現少於1,342,177,280,把第128個桶數據量加上,大於1,342,177,280。

              說明,中位數必在磁盤的第128個桶中。而且在這個桶的第1,342,177,280-N(0-127)個數位上。N(0-127)表示前127個桶的數據量之和。

              然后把第128個文件中的整數讀入內存。

             (平均而言,每個文件的大小估計在10G/128=80M左右,當然也不一定,但是超過2G的可能性很小)。

代價:(1)循環計算255個桶中的數據量累加,需要O(M)的代價,其中m<255。

           (2)讀入一個大概80M左右文件大小的IO代價。 

注意,變態的情況下,這個需要讀入的第128號文件仍然大於2G,那么整個讀入仍然可以按照第一步分批來進行讀取。 

第三步:繼續以內存中的整數的次高8bit進行桶排序(23-16)。過程和第一步相同,也是255個桶。

第四步:一直下去,直到最低字節(7-0bit)的桶排序結束。我相信這個時候完全可以在內存中使用一次快排就可以了。

 

 

整個過程的時間復雜度在O(n)的線性級別上(沒有任何循環嵌套)。但主要時間消耗在第一步的第二次內存-磁盤數據交換上,即10G數據分255個文件寫回磁盤上。

 

另一種“一步到位”的方法:

由於我們內存中只記錄了每個桶中元素個數,考慮到可能所有元素相同導致一個桶中的數量超過int的表示范圍,數組類型用上long long,這樣數組長度最大為2G/8=2^28,即long long cnt[2^28]。所以可以根據高28為來分桶(而不是前面的8位8位)。

 

 

參考鏈接:

1. https://blog.csdn.net/f2006116/article/details/51159250?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

2. https://blog.csdn.net/xc889078/article/details/8864230


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM