外排序-多路歸并

內(nèi)排序的歸并排序是采用二路歸并。

將已有序的子序列合并,得到完全有序的序列;即先使每個(gè)子序列有序,再使子序列段間有序

外排序我們可以將這個(gè)“二”擴(kuò)大到M。

將一個(gè)大文件分成M個(gè)小文件,每個(gè)小文件是有序的,然后對(duì)應(yīng)在內(nèi)存中我們開(kāi)M個(gè)優(yōu)先隊(duì)列,每個(gè)隊(duì)列從對(duì)應(yīng)編號(hào)的文件中讀取TopN條記錄,然后我們從M路隊(duì)列中各取一個(gè)數(shù)字進(jìn)入中轉(zhuǎn)站隊(duì)列,并將該數(shù)字打上隊(duì)列編號(hào)標(biāo)記,當(dāng)從中轉(zhuǎn)站出來(lái)的最小數(shù)字就是我們最后要排序的數(shù)字之一,因?yàn)樵摂?shù)字打上了隊(duì)列編號(hào),所以方便我們通知對(duì)應(yīng)的編號(hào)隊(duì)列繼續(xù)出數(shù)字進(jìn)入中轉(zhuǎn)站隊(duì)列,可以看出中轉(zhuǎn)站一直保存了M個(gè)記錄,當(dāng)中轉(zhuǎn)站中的所有數(shù)字都出隊(duì)完畢,則外排序結(jié)束。這考驗(yàn)的是我們的架構(gòu)能力。



問(wèn)題描述:

輸入:給定一個(gè)文件,里面最多含有n個(gè)不重復(fù)的正整數(shù)(也就是說(shuō)可能含有少于n個(gè)不重復(fù)正整數(shù)),且其中每個(gè)數(shù)都小于等于n,n=10^7。

輸出:得到按從小到大升序排列的包含所有輸入的整數(shù)的列表。

條件:最多有大約1MB的內(nèi)存空間可用,但磁盤空間足夠。且要求運(yùn)行時(shí)間在5分鐘以下,10秒為最佳結(jié)果。

采取方法:1、歸并排序,內(nèi)存不夠。2、位圖法。3、多路歸并

1、歸并排序,內(nèi)部排序。

2、位圖法

例如:用一個(gè)20位長(zhǎng)的字符串來(lái)表示一個(gè)所有元素都小于20的簡(jiǎn)單的非負(fù)整數(shù)集合,邊框用如下字符串來(lái)表示集合{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,上述集合中各數(shù)對(duì)應(yīng)的位置則置1,沒(méi)有對(duì)應(yīng)的數(shù)的位置則置0。

針對(duì)我們的10^7個(gè)數(shù)據(jù)量的磁盤文件排序問(wèn)題,我們可以這么考慮,由于每個(gè)7位十進(jìn)制整數(shù)表示一個(gè)小于1000萬(wàn)的整數(shù)。我們可以使用一個(gè)具有1000萬(wàn)個(gè)位的字符串來(lái)表示這個(gè)文件,其中,當(dāng)且僅當(dāng)整數(shù)i在文件中存在時(shí),第i位為1。采取這個(gè)位圖的方案是因?yàn)槲覀兠鎸?duì)的這個(gè)問(wèn)題的特殊性:1、輸入數(shù)據(jù)限制在相對(duì)較小的范圍內(nèi),2、數(shù)據(jù)沒(méi)有重復(fù),3、其中的每條記錄都是單一的整數(shù),沒(méi)有任何其它與之關(guān)聯(lián)的數(shù)據(jù)。

三步進(jìn)行解決:

第一步,將所有的位都置為0,從而將集合初始化為空。

第二步,通過(guò)讀入文件中的每個(gè)整數(shù)來(lái)建立集合,將每個(gè)對(duì)應(yīng)的位都置為1。

第三步,檢驗(yàn)每一位,如果該位為1,就輸出對(duì)應(yīng)的整數(shù)。

偽代碼

注意:

用此位圖方法,嚴(yán)格說(shuō)來(lái)還是不太行,空間消耗10^7/8還是大于1M(1M=1024*1024空間,小于10^7/8)。

既然如果用位圖方案的話,我們需要約1.25MB(若每條記錄是8位的正整數(shù)的話,則10000000/(1024*1024*8) ~= 1.2M)的空間,而現(xiàn)在只有1MB的可用存儲(chǔ)空間,那么究竟該作何處理呢?

3、多路歸并

假設(shè)文件中整數(shù)個(gè)數(shù)為N(N是億級(jí)的),整數(shù)之間用空格分開(kāi)。首先分多次從該文件中讀取M(十萬(wàn)級(jí))個(gè)整數(shù),每次將M個(gè)整數(shù)在內(nèi)存中使用快速排序之后存入臨時(shí)文件,然后使用多路歸并將各個(gè)臨時(shí)文件中的數(shù)據(jù)再次整體排好序后存入輸出文件。

排序過(guò)程兩部分構(gòu)成:

1)內(nèi)存排序

由于要求的可用內(nèi)存為1MB,那么每次可以在內(nèi)存中對(duì)250K的數(shù)據(jù)進(jìn)行排序,然后將有序的數(shù)寫入硬盤。

那么10M的數(shù)據(jù)需要循環(huán)40次,最終產(chǎn)生40個(gè)有序的文件。

2)歸并排序

將每個(gè)文件最開(kāi)始的數(shù)讀入(由于有序,所以為該文件最小數(shù)),存放在一個(gè)大小為40的first_data數(shù)組中;

選擇first_data數(shù)組中最小的數(shù)min_data,及其對(duì)應(yīng)的文件索引index;

將first_data數(shù)組中最小的數(shù)寫入文件result,然后更新數(shù)組first_data(根據(jù)index讀取該文件下一個(gè)數(shù)代替min_data);

判斷是否所有數(shù)據(jù)都讀取完畢,否則返回2。

所以,本程序按順序分兩步,第一步、Memory Sort,第二步、Merge Sort。程序的流程圖,如下圖所示(感謝F的繪制)。





小結(jié):

bit-map

適用范圍:可進(jìn)行數(shù)據(jù)的快速查找,判重,刪除,一般來(lái)說(shuō)數(shù)據(jù)范圍是int的10倍以下

基本原理及要點(diǎn):使用bit數(shù)組來(lái)表示某些元素是否存在,比如8位電話號(hào)碼

擴(kuò)展:bloom filter可以看做是對(duì)bit-map的擴(kuò)展

問(wèn)題實(shí)例:

1)已知某個(gè)文件內(nèi)包含一些電話號(hào)碼,每個(gè)號(hào)碼為8位數(shù)字,統(tǒng)計(jì)不同號(hào)碼的個(gè)數(shù)。

8位最多99 999 999,大概需要99m個(gè)bit,大概10幾m字節(jié)的內(nèi)存即可。

2)2.5億個(gè)整數(shù)中找出不重復(fù)的整數(shù)的個(gè)數(shù),內(nèi)存空間不足以容納這2.5億個(gè)整數(shù)。

將bit-map擴(kuò)展一下,用2bit表示一個(gè)數(shù)即可,0表示未出現(xiàn),1表示出現(xiàn)一次,2表示出現(xiàn)2次及以上。或者我們不用2bit來(lái)進(jìn)行表示,我們用兩個(gè)bit-m

[外排序適用范圍]

大數(shù)據(jù)的排序,去重基本原理及要點(diǎn):外排序的歸并方法,置換選擇敗者樹原理,最優(yōu)歸并樹擴(kuò)展。

問(wèn)題實(shí)例:

1).有一個(gè)1G大小的一個(gè)文件,里面每一行是一個(gè)詞,詞的大小不超過(guò)16個(gè)字節(jié),內(nèi)存限制大小是1M。返回頻數(shù)最高的100個(gè)詞。這個(gè)數(shù)據(jù)具有很明顯的特點(diǎn),詞的大小為16個(gè)字節(jié),但是內(nèi)存只有1m做hash有些不夠,所以可以用來(lái)排序。內(nèi)存可以當(dāng)輸入緩沖區(qū)使用。


具體實(shí)例詳解:

鏈接 :http://www.lxweimin.com/p/1683cf5cc0c9


勝者樹,敗者樹

勝者樹和敗者樹都是完全二叉樹,是樹形選擇排序的一種變型。每個(gè)葉子結(jié)點(diǎn)相當(dāng)于一個(gè)選手,每個(gè)中間結(jié)點(diǎn)相當(dāng)于一場(chǎng)比賽,每一層相當(dāng)于一輪比賽。

同的是,勝者樹的中間結(jié)點(diǎn)記錄的是勝者的標(biāo)號(hào);而敗者樹的中間結(jié)點(diǎn)記錄的敗者的標(biāo)號(hào)。

勝者樹與敗者樹可以在log(n)的時(shí)間內(nèi)找到最值。任何一個(gè)葉子結(jié)點(diǎn)的值改變后,利用中間結(jié)點(diǎn)的信息,還是能夠快速地找到最值。在k路歸并排序中經(jīng)常用到。


區(qū)別:

在用勝者樹的時(shí)候,每個(gè)新元素上升時(shí),首先需要獲得父節(jié)點(diǎn),然后再獲得兄弟節(jié)點(diǎn),然后再比較。

在使用敗者樹的時(shí)候,每個(gè)新元素上升時(shí),只需要獲得父節(jié)點(diǎn)并比較即可。

所以總的來(lái)說(shuō),減少了訪存的時(shí)間。

勝者樹和敗者樹在每輸出和補(bǔ)充一個(gè)值之后都要自底向上調(diào)整,每上升一層都需要一次比較,敗者樹是和父節(jié)點(diǎn)的一次比較,勝者樹是和兄弟的一次比較,在比較的內(nèi)存訪問(wèn)次數(shù)上二者沒(méi)有太大的差別(或者勝者樹可能好一點(diǎn))。不同的是勝者樹每次必然需要更新勝者(因?yàn)檫@條路徑就是以原來(lái)的最終勝者為外部節(jié)點(diǎn)的路徑,而原來(lái)的最終勝者已經(jīng)被輸出了),但敗者樹每次不一定需要更新,這就代表它在每次上升時(shí)可能會(huì)少一次向內(nèi)存的寫入,因此更優(yōu)

由于新加入的節(jié)點(diǎn)一定是替換了上一輪的勝者,那么對(duì)于勝者堆,從新節(jié)點(diǎn)到根之間路徑節(jié)點(diǎn)存的都是上一輪的勝者,這些數(shù)據(jù)事實(shí)上對(duì)于本輪比較來(lái)說(shuō)是無(wú)用的,但每次還要與兄弟節(jié)點(diǎn)比較去更新它。

而敗者堆中,對(duì)于新更新的節(jié)點(diǎn),它的父節(jié)點(diǎn)都是兄弟子堆的勝者,是最有價(jià)值、值得比較的數(shù)據(jù),每次更新也都可以直接用于下輪比較。











http://blog.csdn.net/v_JULY_v/article/details/6451990 ?(贊)

http://blog.csdn.net/v_JULY_v/article/details/6279498 ?(超贊)

http://www.cnblogs.com/charlesblc/p/6138908.html

http://blog.csdn.net/msdnwolaile/article/details/52084983

http://blog.csdn.net/u013322907/article/details/38125641

http://blog.csdn.net/msdnwolaile/article/details/52084983

http://blog.csdn.net/v_JULY_v

http://blog.csdn.net/whz_zb/article/details/7425152

https://www.zhihu.com/question/35144290


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 因?yàn)橹熬蛷?fù)習(xí)完數(shù)據(jù)結(jié)構(gòu)了,所以為了保持記憶,整理了一份復(fù)習(xí)綱要,復(fù)習(xí)的時(shí)候可以看著綱要想具體內(nèi)容。 樹 樹的基本...
    牛富貴兒閱讀 7,004評(píng)論 3 10
  • 教你如何迅速秒殺掉:99%的海量數(shù)據(jù)處理面試題 本文經(jīng)過(guò)大量細(xì)致的優(yōu)化后,收錄于我的新書《編程之法》第六章中,新書...
    Helen_Cat閱讀 7,455評(píng)論 1 39
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個(gè)記錄插入到已排序好...
    依依玖玥閱讀 1,282評(píng)論 0 2
  • 摘要:本文將向您講述諸多數(shù)據(jù)處理面試題以及方法的總結(jié)。 第一部分、十道海量數(shù)據(jù)處理面試題 1、海量日志數(shù)據(jù),提取出...
    拾壹北閱讀 1,713評(píng)論 0 28
  • 排序的基本概念 在計(jì)算機(jī)程序開(kāi)發(fā)過(guò)程中,經(jīng)常需要一組數(shù)據(jù)元素(或記錄)按某個(gè)關(guān)鍵字進(jìn)行排序,排序完成的序列可用于快...
    Jack921閱讀 1,459評(píng)論 1 4