定義:
1、按可用內存大小,將外存上的記錄文件分成若干個歸並段 (segments)
2、依次讀入內存並利用有效的外部排序方法進行排序
3、將排序后的有序子文件寫入外存
實現:
利用敗者樹進行k路歸並,使得每次歸並在k個記錄中選出最小記錄僅需進行次(二叉樹的深度)比較,從而使總的歸並時間為
。其中,m為初始歸並段個數,n為總記錄數,
每次比較時間。
敗者樹:
典型的4路敗者樹如下圖:
----------à
直觀的,敗者樹是一棵完全二叉樹,可由數組保持。其中根節點保存一次比較中的冠軍;葉節點
保存4個歸並段的輸入流;非葉結點
保存一次比較中的敗者。
難點1:一輪比較選出最小關鍵記錄並調整敗者樹
調整的發起點:值發生變化的葉節點,必然使對應的父節點發生變化。注意,父節點中記錄的敗者必然是另一棵子樹的勝者,但是敗給了本子樹的勝者,如。
調整:
1、i保存前一次比較的勝者,與的敗者比較
If i失敗: , 發生互換
2、如此遞歸的向根節點調用,直到根節點,將i中的冠軍計入
難點2:敗者樹的初始化
1、將非葉結點初始化為可能的最小值(冠軍)
2、由至
調整敗者樹
注意點:
每個歸並段內的數據是有序的,這與歸並排序是一致的。並且歸並段的最后需要一個全局最小的"哨兵",防止歸並段讀空(仔細想想),並且當冠軍為"哨兵"時,程序退出。
思想:以空間保存歷次比較結果,將一般k-路歸並選擇一次最小值的k-1次操作變為,典型的時空互換思想。
代碼:
-
import java.io.*;
-
-
public class LoserTree {
-
-
public static void main(String[] args) {
-
-
PrintWriter[] data = new PrintWriter[LoserTree.K];
-
BufferedReader[] segments = new BufferedReader[LoserTree.K];
-
-
-
try {
-
-
for (int i = 0; i < LoserTree.K; i++) {
-
-
data[i] = new PrintWriter(new FileWriter(i + ".txt"));
-
}
-
-
for (int k = 0; k < 5; k++) {
-
-
for (int i = 0; i < 5; i++) {
-
-
data[k].println(21 - 5 * k + i);
-
}
-
-
data[k].println(LoserTree.MAXKEY);
-
}
-
-
for (int i = 0; i < LoserTree.K; i++) {
-
-
data[i].close();
-
}
-
-
for (int i = 0; i < LoserTree.K; i++) {
-
-
segments[i] = new BufferedReader(new FileReader(i + ".txt"));
-
}
-
-
LoserTree Sorter = new LoserTree();
-
-
Sorter.merge(segments);
-
-
for (int i = 0; i < LoserTree.K; i++) {
-
-
segments[i].close();
-
}
-
-
} catch (Exception e) {
-
-
e.printStackTrace();
-
}
-
-
}
-
-
static final int K = 5;
-
static final int MINKEY = -100;
-
static final int MAXKEY = 100;
-
-
public int[] LS = new int[K];
-
public int[] b = new int[K + 1];
-
-
PrintWriter result;
-
-
public void merge(BufferedReader[] in) {
-
-
try {
-
result = new PrintWriter(new File("result.txt"));
-
-
for (int i = 0; i < K; i++) {
-
-
input(in[i], i);
-
}
-
-
create();
-
-
int q;
-
-
while (b[LS[0]] != MAXKEY) {
-
-
q = LS[0];
-
-
output(q);
-
-
input(in[q], q);
-
-
adjust(q);
-
-
}
-
-
result.close();
-
-
} catch (Exception e) {
-
// TODO Auto-generated catch block
-
throw new RuntimeException(e);
-
}
-
-
-
}
-
-
private void create() {
-
-
b[K] = MINKEY;
-
-
for (int i = 0; i < K; i++) {
-
-
LS[i] = K;
-
}
-
-
for (int i = K-1; i > -1; i--) {
-
-
adjust(i);
-
}
-
}
-
-
private void adjust(int i) {
-
-
int parent = (i + K) / 2;
-
-
int temp;
-
-
while (parent > 0) {
-
-
if (b[i] > b[LS[parent]]) {
-
-
temp = LS[parent];
-
LS[parent] = i;
-
i = temp;
-
}
-
-
parent = parent / 2;
-
}
-
-
LS[0] = i;
-
-
-
}
-
-
private void input(BufferedReader in, int i) {
-
-
try {
-
-
b[i] = Integer.valueOf(in.readLine());
-
-
} catch (Exception e) {
-
// TODO Auto-generated catch block
-
throw new RuntimeException(e);
-
-
}
-
}
-
-
private void output(int i) {
-
-
result.println(b[i]);
-
result.flush();
-
}
-
}