超大文件內單詞排序(文件大小大於內存)

Description:

文件200G,內部存儲着單詞,單詞之間以逗號分隔,請生成一個有序文件,對所有單詞按照字典序排列。限制你使用的用於存儲文件內容的內存大小爲1G。


Method1:

(面試時臨時想了出來,雖然不是最好的方法,但是隻要work,面試就算通過!)

先遍歷文件,將以a頭的單詞找出來,對這些單詞進行排序並保存,然後找b開頭的單詞,依次類推,最後將各個小文件組合。如果找的過程中發現以a開頭的單詞太多,則繼續分成以aa開頭,以ab開頭...。

另外,例如,  爲了防止以a開頭的單詞過多,可以設置一個閾值,例如10000個單詞或者1G,當遍歷過程中找到的以a開頭的單詞大於1000個 或者 以a開頭的單詞構成的文件將會大於1G時,則放棄,轉而,先找以aa開頭的....

 

Method2:

針對這種問題有一種經典的方案: 外排序
一般來說,外排序處理的數據不能一次裝入內存,只能放在讀寫較慢的外存儲器(通常是硬盤)上。

外排序通常採用的“排序-歸併”的策略。在排序階段,先讀入能放在內存中的一定大小的數據量,將其排序輸出到一個臨時文件,依此進行,最後得到多個有序的臨時文件。之後在歸併階段將這些臨時文件組合爲一個大的有序文件。

例如,如果限制你所使用的內存的大小爲1G, 對於20G的文件進行排序, 則, 每次讀入1G內容,以某種常規方式在內存中完成排序(快速排序、堆排序、歸併排序等等),然後,輸出爲一個內部數據有序的臨時文件存到磁盤。最後對20個有序文件進行歸併。

歸併時也必須考慮內存大小的限制:

讀入每個臨時文件的前1/(20+1) G的內容到內存,之所以20+1, 是因爲要預留緩衝區用於存放歸併的結果,相當於將可用內存空間分成了21份,其中20份用於存儲從每個臨時文件中讀入的內容,剩餘的一份用於保存中間結果。 (實踐中,將輸入緩衝適當調小,而適當增大輸出緩衝區能獲得更好的效果)。 

Note: 根據歸併算法,歸併排序時必須同時考慮所有的臨時文件。

執行20路歸併算法,將結果輸出到輸出緩衝區。一旦輸出緩衝區滿,將緩衝區中的數據寫出至目標文件,清空緩衝區。一旦20個輸入緩衝區中的一個變空,就從這個緩衝區關聯的文件,讀入下一個1G數據,除非這個文件已讀完。

這是“外歸併排序”能在主存外完成排序的關鍵步驟 -- 因爲“歸併算法”(merge algorithm)對每一個大塊只是順序地做一輪訪問(進行歸併),每個大塊文件不用完全載入主存!

=

Other:

爲了增加每一個有序的臨時文件的長度,可以採用置換選擇排序(Replacement selection sorting)。它可以產生大於內存大小的順串。具體方法是在內存中使用一個最小堆進行排序,設該最小堆的大小爲M。算法描述如下:

初始時將輸入文件讀入內存,建立最小堆。
將堆頂元素輸出至輸出緩衝區。然後讀入下一個記錄:
若該元素的關鍵碼值不小於剛輸出的關鍵碼值,將其作爲堆頂元素並調整堆,使之滿足堆的性質;
否則將新元素放入堆底位置,將堆的大小減1。
重複第2步,直至堆大小變爲0。
此時一個順串已經產生。將堆中的所有元素建堆,開始生成下一個順串。
此方法能生成平均長度爲 2M的順串,可以進一步減少訪問外部存儲器的次數,節約時間,提高算法效率。

 

Ref:

https://www.cnblogs.com/lightwindy/p/9650736.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章