【排序演算法】外部排序一 —— 外部排序介紹
外部排序
我們一般提到排序都是指內排序,比如快速排序,堆排序,歸併排序等,所謂內排序就是可以在記憶體中完成的排序。RAM的訪問速度大約是磁碟的25萬倍,我們當然希望如果可以的話都是內排來完成。但對於大資料集來說,記憶體是遠遠不夠的,這時候就涉及到外排序的知識了。
外部排序指的是大檔案的排序,即待排序的記錄儲存在外儲存器上,待排序的檔案無法一次裝入記憶體,需要在記憶體和外部儲存器之間進行多次資料交換,以達到排序整個檔案的目的。外部排序最常用的演算法是多路歸併排序,即將原檔案分解成多個能夠一次性裝人記憶體的部分,分別把每一部分調入記憶體完成排序。然後,對已經排序的子檔案進行歸併排序。
一般來說外排序分為兩個步驟:預處理和合並排序。即首先根據記憶體的大小,將有n個記錄的磁碟檔案分批讀入記憶體,採用有效的記憶體排序方法進行排序,將其預處理為若干個有序的子檔案,這些有序子檔案就是初始順串,然後採用合併的方法將這些初始順串逐趟合併成一個有序檔案。
預處理階段最重要的事情就是選擇初始順串。通常使用的方法為置換選擇排序,它是堆排序的一種變形,實現思路同STL的partial_sort。步驟如下:
1.初始化堆
(1)從磁碟讀入M個記錄放到陣列RAM中
(2)設定堆末尾標準LAST=M-1
(3)建立最小值堆
2.重複以下步驟直到堆為空
(1)把具有最小關鍵碼值的記錄Min也就是根節點送到輸出緩衝區
(2)設R是輸入緩衝區中的下一條記錄,如果R的關鍵碼大於剛剛輸出的關鍵碼值Min,則把R放到根節點,否則使用陣列中LAST位置的記錄代替根節點,並將剛才的R放入到LAST所在位置,LAST=LAST-1;
(3)重新排列堆,篩出根節點
如果堆的大小是M,一個順串的最小長度就是M個記錄,因為至少原來在堆中的那些記錄將成為順串的一部分,如果輸入時逆序的,那麼順串的長度只能是M,最好情況輸入是正序的,有可能一次性就能把整個檔案生成一個順串,由此可見生成順串的長度是大小不一的,但是每個順串卻是有序的,利用掃雪機模型能夠得到平均順串的長度為2M。
得到順串之後呢,就開始進行歸併了。二路歸併的缺點是掃描次數太多,因為如果順串的個數為m個,那麼二路歸併的掃描次數就是log(2,m),採用多路歸併可以減少掃描次數,一般情況下使用選擇樹來進行多路歸併。選擇樹有贏者樹和敗者樹2種,贏者樹比較直觀,但是每次調整需要改動比較大,所以一般情況下都用敗者樹,所謂敗者樹就是非葉子節點的值都是兩個子結點中的敗者對應的值。這句話其實說的比較含糊,真正生成敗者樹的過程是每次都將敗者放在父節點上,同時勝者繼續比較,勝者中的敗者再放在父節點上,再記錄下此時的勝者繼續比較。……比賽的過程:將新進入樹的節點與其父節點進行比賽,將敗者存放在父節點,而勝者再與上一級的父節點繼續比賽。……因此從這個過程也可以看出,其實敗者樹只會改變一個分支,不會影響到其他,因而重構的代價比較小。
需要歸併的趟數就是log(b,m),b為幾路歸併,m為順串的個數。產生一個大小為n的順串時間為O(k+nlogk)。使用最佳歸併可以減少輸入/輸出量。