外排序

外排序

方法介紹

所謂外排序,顧名思義,便是在內存外面的排序,由於當要處理的數據量很大,而不能一次裝入內存時,此時只能放在讀寫較慢的外存儲器(一般是硬盤)上。算法

外排序一般採用的是一種「排序-歸併」的策略。編程

  • 在排序階段,先讀入能放在內存中的數據量,將其排序輸出到一個臨時文件,依此進行,將待排序數據組織爲多個有序的臨時文件;
  • 爾後在歸併階段將這些臨時文件組合爲一個大的有序文件,也即排序結果。

假定如今有20個數據的文件A:{5 11 0 18 4 14 9 7 6 8 12 17 16 13 19 10 2 1 3 15},但一次只能使用僅裝4個數據的內容,因此,咱們能夠每趟對4個數據進行排序,即5路歸併,具體方法以下述步驟:數組

  • 咱們先把「大」文件A,分割爲a1,a2,a3,a4,a5等5個小文件,每一個小文件4個數據spa

    • a1文件爲:5 11 0 18
    • a2文件爲:4 14 9 7
    • a3文件爲:6 8 12 17
    • a4文件爲:16 13 19 10
    • a5文件爲:2 1 3 15
  • 而後依次對5個小文件分別進行排序code

    • a1文件完成排序後:0 5 11 18
    • a2文件完成排序後:4 7 9 14
    • a3文件完成排序後:6 8 12 17
    • a4文件完成排序後:10 13 16 19
    • a5文件完成排序後:1 2 3 15
  • 最終多路歸併,完成整個排序排序

    • 整個大文件A文件完成排序後:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

問題實例

一、給10^7個數據量的磁盤文件排序內存

輸入:給定一個文件,裏面最多含有n個不重複的正整數(也就是說可能含有少於n個不重複正整數),且其中每一個數都小於等於n,n=10^7。 輸出:獲得按從小到大升序排列的包含全部輸入的整數的列表。 條件:最多有大約1MB的內存空間可用,但磁盤空間足夠。且要求運行時間在5分鐘如下,10秒爲最佳結果。字符串

解法一 :位圖方案input

你可能會想到把磁盤文件進行歸併排序,但題目要求你只有1MB的內存空間可用,因此,歸併排序這個方法不行。it

熟悉位圖的朋友可能會想到用位圖來表示這個文件集合。例如正如編程珠璣一書上所述,用一個20位長的字符串來表示一個全部元素都小於20的簡單的非負整數集合,邊框用以下字符串來表示集合{1,2,3,5,8,13}:

0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0

上述集合中各數對應的位置則置1,沒有對應的數的位置則置0。

參考編程珠璣一書上的位圖方案,針對咱們的10^7個數據量的磁盤文件排序問題,咱們能夠這麼考慮,因爲每一個7位十進制整數表示一個小於1000萬的整數。咱們可使用一個具備1000萬個位的字符串來表示這個文件,其中,當且僅當整數i在文件中存在時,第i位爲1。採起這個位圖的方案是由於咱們面對的這個問題的特殊性:

  1. 輸入數據限制在相對較小的範圍內,
  2. 數據沒有重複,
  3. 其中的每條記錄都是單一的整數,沒有任何其它與之關聯的數據。

因此,此問題用位圖的方案分爲如下三步進行解決:

  • 第一步,將全部的位都置爲0,從而將集合初始化爲空。
  • 第二步,經過讀入文件中的每一個整數來創建集合,將每一個對應的位都置爲1。
  • 第三步,檢驗每一位,若是該位爲1,就輸出對應的整數。

通過以上三步後,產生有序的輸出文件。令n爲位圖向量中的位數(本例中爲1000 0000),程序能夠用僞代碼表示以下:

//磁盤文件排序位圖方案的僞代碼  
//copyright@ Jon Bentley  
//July、updated,2011.05.29。  

//第一步,將全部的位都初始化爲0  
for i ={0,....n}      
   bit[i]=0;  
//第二步,經過讀入文件中的每一個整數來創建集合,將每一個對應的位都置爲1。  
for each i in the input file     
   bit[i]=1;  

//第三步,檢驗每一位,若是該位爲1,就輸出對應的整數。  
for i={0...n}      
  if bit[i]==1        
    write i on the output file

上述的位圖方案,共須要掃描輸入數據兩次,具體執行步驟以下:

第一次,只處理1—4999999之間的數據,這些數都是小於5000000的,對這些數進行位圖排序,只須要約5000000/8=625000Byte,也就是0.625M,排序後輸出。 第二次,掃描輸入文件時,只處理4999999-10000000的數據項,也只須要0.625M(可使用第一次處理申請的內存)。 所以,總共也只須要0.625M 位圖的的方法有必要強調一下,就是位圖的適用範圍爲針對不重複的數據進行排序,若數據有重複,位圖方案就不適用了。

不過很快,咱們就將意識到,用此位圖方法,嚴格說來仍是不太行,空間消耗10^7/8仍是大於1M(1M=1024*1024空間,小於10^7/8)。

既然若是用位圖方案的話,咱們須要約1.25MB(若每條記錄是8位的正整數的話,則10000000/(1024 1024 8) ~= 1.2M)的空間,而如今只有1MB的可用存儲空間,那麼究竟該做何處理呢?

解法二 :多路歸併

誠然,在面對本題時,還能夠經過計算分析出能夠用如2的位圖法解決,但實際上,不少的時候,咱們都面臨着這樣一個問題,文件太大,沒法一次性放入內存中計算處理,那這個時候咋辦呢?分而治之,大而化小,也就是把整個大文件分爲若干大小的幾塊,而後分別對每一塊進行排序,最後完成整個過程的排序。k趟算法能夠在kn的時間開銷內和n/k的空間開銷內完成對最多n個小於n的無重複正整數的排序。

好比可分爲2塊(k=2,1趟反正佔用的內存只有1.25/2M),1~4999999,和5000000~9999999。先遍歷一趟,首先排序處理1~4999999之間的整數(用5000000/8=625000個字的存儲空間來排序0~4999999之間的整數),而後再第二趟,對5000001~1000000之間的整數進行排序處理。

解法總結

一、關於本章中位圖和多路歸併兩種方案的時間複雜度及空間複雜度的比較,以下:

時間複雜度        空間複雜度

位圖          O(N)          0.625M

多位歸併   O(Nlogn)             1M

(多路歸併,時間複雜度爲O(k n/k logn/k ),嚴格來講,還要加上讀寫磁盤的時間,而此算法絕大部分時間也是浪費在這上面)

二、bit-map

適用範圍:可進行數據的快速查找,判重,刪除,通常來講數據範圍是int的10倍如下

基本原理及要點:使用bit數組來表示某些元素是否存在,好比8位電話號碼

擴展:bloom filter能夠看作是對bit-map的擴展

觸類旁通

、已知某個文件內包含一些電話號碼,每一個號碼爲8位數字,統計不一樣號碼的個數。 8位最多99 999 999,大概須要99m個bit,大概10幾m字節的內存便可。

相關文章
相關標籤/搜索