闲来无事,做了一个多路文件归并的工具,用败者树选择从多路输入中选择一个最小者,空间复杂度为O(K),K为归并输入的路数。该实现没有考虑最佳归并路径,等日后有空了再实现一个最佳归并路径的算法;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class MultiChannelMerge {
public static class TNode {
public int channel;
public int value;
public TNode(int c, int v) {
channel = c;
value = v;
}
}
private int LEN = 0;
private TNode[] loser;
private int MAX = 0x7FFFFFFF;
private int N = 0;
private BufferedReader[] reader;
public MultiChannelMerge(String[] files) throws FileNotFoundException {
N = files.length;
LEN = N + N -1;
loser = new TNode[LEN];
reader = new BufferedReader[N];
try {
// create buffered reader for each file
for ( int i=0; i<N; i++ ) {
reader[i] = new BufferedReader(new FileReader(files[i]));
}
} catch (FileNotFoundException e) {
close();
throw e;
}
}
/*
* close all readers
*/
private void close() {
// close buffered reader
for ( int i=0; i<N; i++ ) {
if ( reader[i] != null ) {
try { reader[i].close(); } catch (IOException e1) {}
}
}
}
/*
* copy content of 'sour' node to 'dest' node
*/
private TNode cloneNode(TNode sour) {
TNode dest = new TNode(sour.channel, sour.value);
return dest;
}
/*
* feed a number from channel 'c' and get the winner
*/
public void feedTree(int c, TNode winner) throws IOException {
String line = reader[c].readLine();
winner.channel = c;
winner.value = ( line != null ) ? Integer.valueOf(line) : MAX;
int cur = N-1+c;
do {
cur = ( cur - 1 ) / 2;
if ( loser[cur].value <= winner.value ) {
swapNode(loser[cur],winner);
}
} while ( cur > 0 );
}
/*
* init a loser tree
*/
public void initTree(TNode res) throws IOException {
TNode[] winner = new TNode[LEN];
// read a number from each file
for ( int c=0; c<N; c++ ) {
String line = reader[c].readLine();
int v = ( line != null ) ? Integer.valueOf(line) : MAX;
TNode node = new TNode(c,v);
winner[N-1+c] = node;
loser[N-1+c] = node;
}
// calculate winner and loser for each node
for ( int k=N-2; k>=0; k-- ) {
int left = ( k << 1 ) + 1, right = ( k << 1 ) + 2;
int win, los;
if ( winner[left].value <= winner[right].value ) {
win = left; los = right;
} else {
win = right; los = left;
}
winner[k] = cloneNode(winner[win]);
loser[k] = cloneNode(winner[los]);
}
res.channel = winner[0].channel;
res.value = winner[0].value;
}
/*
* multi-channel merge sort
*/
public void mergeSort() throws IOException {
try {
TNode winner = new TNode(0,MAX);
initTree(winner);
while ( winner.value != MAX ) {
System.out.printf("%d ", winner.value);
feedTree(winner.channel, winner);
}
} catch (IOException e) {
close();
throw e;
}
}
/*
* swap the content of n1 and n2
*/
private void swapNode(TNode n1, TNode n2) {
int temp_v = n1.value, temp_c = n1.channel;
n1.value = n2.value; n1.channel = n2.channel;
n2.value = temp_v; n2.channel = temp_c;
}
/**
* @param args
*/
public static void main(String[] args) {
String[] file = {
"c:\\temp\\a1.txt",
"c:\\temp\\a2.txt",
"c:\\temp\\a3.txt"
};
MultiChannelMerge instance = null;
try {
instance = new MultiChannelMerge(file);
instance.mergeSort();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
instance.close();
}
}
}