1. 程式人生 > >海量資料處理專題(九)——外排序(轉)

海量資料處理專題(九)——外排序(轉)

【引言】

在資料結構的課程上,我們學習了不少的排序演算法,冒泡,堆,快排,歸併等。但是這些排序方法有著共同的特點,那就是所有的操作都是在記憶體中完成的,演算法過程中不需要IO,這就使得這樣的演算法總體上速度比較快,但是也隨之出現了一個問題:當需要排序的資料量異常的大的時候,以上的演算法就顯得力不從心了。這時候,你需要一種另外的排序演算法,它的名字叫“外排序”。

通常的,裝置的記憶體讀取速度要比外存讀取速度快得多(RAM的訪問速度大約是磁碟的25萬倍),但是記憶體的容量卻要比外存小很多,當所有的資料不能在記憶體中完全放下的時候,就需要使用到外排序。這是外排序的一個顯著特徵。

【什麼是外排序】

外排序其實是採用一種分治(

Divide and conquer algorithm)的演算法設計思想,將一個大問題劃分成相對獨立的若干個小問題,解決小問題,得到小問題的答案,然後合併小問題的答案,最終得到原始大問題的答案。

在這裡,我們舉一個外排的典型例子,二路外部歸併排序,假設我們有一個大檔案,裡面是待排序的資料,一共N個,這些資料在記憶體中放不下。排序過程如下:

  1. 將該大檔案分割成大小為m的檔案(m小於可用記憶體大小)
  2. 將這些小檔案依次讀入記憶體,在記憶體中採用任一種排序演算法排序並輸出檔案F1,F2….Fn。(其實可以和第一步合併,可以省一次IO)
  3. 分塊快讀取兩個已經排完序的檔案Fi和Fi+1,由於兩個檔案已經排完序,這裡可以用歸併排序,將兩個檔案排序完畢,並寫入檔案。(這個過程就好比有兩隊人馬將其合併為一對一樣)
  4. 重複過程3,直到剩餘檔案數為1。

以上就是二路外部歸併排序的基本思路,毫無疑問,這種排序演算法需要讀取外存(IO)次數為log(2,N/m),這時候演算法的效能瓶頸已經不在記憶體中排序的時間複雜度上,而是內外村交換資料IO的次數了。這裡我補充一句,各種操作的效能差別:

讀取網路 > 磁碟檔案IO > 讀取資料庫 > 記憶體讀取

這個可謂是程式效能的黃金法則,各位在寫對效能要求比較高的程式時一定要考慮。

好,言歸正傳,二路歸併排序這個演算法的效能時比較低的。因此就有了多路歸併排序演算法,其IO的次數為log(b, N/m),其中b為幾路歸併。這個可以參考以下地址:

【實戰訓練】

淘寶不同使用者的瀏覽log有上千萬or億資料(有重複),統計其中有相同瀏覽愛好的使用者。