您的位置:首页 > 其它

排序算法---外部排序

2017-08-03 13:46 176 查看

算法设计:

可以使用外部排序对大容量数据进行排序。数据量过大,存储于外部文件,数据不能完全加载到内存中。
1.从文件中读取一固定数目的数据到数组,对数组排序,将排好序的数组作为一个数据段输出到一个临时文件,重复上述过程,直到源文件中数据读取完
2.将存储了数据段的文件中一般的数据段复制到一个临时文件,然后对着两个文件的数据段归并排序,每两个数据段归并形成一个大的数据段存储于一个文件中,重复2,直到只有一个数据段为止。


[b]代码实现:[/b]

创建存储大量数据的文件:


public class CreateLargeFile {

public static void main(String[] args) throws IOException {
DataOutputStream output = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream("D:\\largedata.dat")));
for (int i = 0; i < 800004; i++)
output.writeInt((int) (Math.random() * 1000000));
output.close();

DataInputStream input = new DataInputStream(new BufferedInputStream(new FileInputStream("D:\\largedata.dat")));
for (int i = 0; i < 100; i++)
System.out.print(input.readInt() + " ");
input.close();
}
}


排序实现:

public class SortLargeFile {
public static final int MAX_ARRAY_SIZE = 100000;
public static final int BUFFER_SIZE = 100000;

public static void main(String[] args) throws IOException {
// 将largedata.dat中的数据排序存入sortedfile.dat中
sort("D:\\largedata.dat", "D:\\sortedfile.dat");
// 输出排序后的前100个数
displayFile("D:\\sortedfile.dat");
}

/**
* 将源文件数据排序存入目标文件
*
* @param sourcefile
* @param targetfile
* @throws IOException
*/
public static void sort(String sourcefile, String targetfile) throws IOException {
int numberOfSegments = initializeSegments(MAX_ARRAY_SIZE, sourcefile, "D:\\f1.dat");
merge(numberOfSegments, MAX_ARRAY_SIZE, "D:\\f1.dat", "D:\\f2.dat", "D:\\f3.dat", targetfile);
}

/**
* 将原始文件排序为一个个有顺序的段,存入临时文件
*
* @param segmentSize
* @param originalFile
* @param f1
* @return
* @throws IOException
*/
private static int initializeSegments(int segmentSize, String originalFile, String f1) throws IOException {
int[] list = new int[segmentSize];
DataInputStream input = new DataInputStream(new BufferedInputStream(new FileInputStream(originalFile)));
DataOutputStream output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(f1)));

int numberOfSegments = 0;
while (input.available() > 0) {
numberOfSegments++;
int i = 0;
for (; input.available() > 0 && i < segmentSize; i++) {
list[i] = input.readInt();
}
// 将读出的数据排序
Arrays.sort(list, 0, i);
// 将排序后的数据输入临时文件
for (int j = 0; j < i; j++) {
output.writeInt(list[j]);
}
}
input.close();
output.close();

return numberOfSegments;
}

/**
* 将排好序的段归并并排序直到只有一个段
*
* @param numberOfSegments
* @param segmentSize
* @param f1
* @param f2
* @param f3
* @param targetfile
* @throws IOException
*/
private static void merge(int numberOfSegments, int segmentSize, String f1, String f2, String f3, String targetfile)
throws IOException {
if (numberOfSegments > 1) {
mergeOneStep(numberOfSegments, segmentSize, f1, f2, f3);
merge((numberOfSegments + 1) / 2, segmentSize * 2, f3, f1, f2, targetfile);
} else {
File sortedFile = new File(targetfile);
if (sortedFile.exists())
sortedFile.delete();
new File(f1).renameTo(sortedFile);
}
}

/**
* 归并第一阶段
*
* @param numberOfSegments
* @param segmentSize
* @param f1
* @param f2
* @param f3
* @throws IOException
*/
private static void mergeOneStep(int numberOfSegments, int segmentSize, String f1, String f2, String f3)
throws IOException {
DataInputStream f1Input = new DataInputStream(new BufferedInputStream(new FileInputStream(f1), BUFFER_SIZE));
DataOutputStream f2Output = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(f2), BUFFER_SIZE));
// 将f1中的段复制一半到f2中
copyHalfToF2(numberOfSegments, segmentSize, f1Input, f2Output);
f2Output.close();

// 将f1和f2中的段归并为更大的段到f3中
DataInputStream f2Input = new DataInputStream(new BufferedInputStream(new FileInputStream(f2), BUFFER_SIZE));
DataOutputStream f3Output = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(f3), BUFFER_SIZE));
mergeSegments(numberOfSegments / 2, segmentSize, f1Input, f2Input, f3Output);

f1Input.close();
f2Input.close();
f3Output.close();
}

/**
* 复制前半部分的段
*
* @param numberOfSegments
* @param segmentSize
* @param f1Input
* @param f2Output
* @throws IOException
*/
private static void copyHalfToF2(int numberOfSegments, int segmentSize, DataInputStream f1Input,
DataOutputStream f2Output) throws IOException {
for (int i = 0; i < (numberOfSegments / 2) * segmentSize && f1Input.available() > 0; i++) {
f2Output.writeInt(f1Input.readInt());
}
}

/**
* 归并所有的段
*
* @param numberOfSegments
* @param segmentSize
* @param f1Input
* @param f2Input
* @param f3Output
* @throws IOException
*/
private static void mergeSegments(int numberOfSegments, int segmentSize, DataInputStream f1Input,
DataInputStream f2Input, DataOutputStream f3Output) throws IOException {
for (int i = 0; i < numberOfSegments; i++) {
mergeTwoSegments(segmentSize, f1Input, f2Input, f3Output);
}
// 如果f1中还有剩余的则复制到f3
while (f1Input.available() > 0) {
f3Output.writeInt(f1Input.readInt());
}
}

/**
* 归并两个分段
*
* @param segmentSize
* @param f1
* @param f2
* @param f3
* @throws IOException
*/
private static void mergeTwoSegments(int segmentSize, DataInputStream f1, DataInputStream f2, DataOutputStream f3)
throws IOException {
int intFromF1 = f1.readInt();
int intFromF2 = f2.readInt();
int f1Count = 1;
int f2Count = 1;

while (true) {
if (intFromF1 < intFromF2) {
f3.writeInt(intFromF1);
if (f1.available() == 0 || f1Count++ >= segmentSize) {
f3.write(intFromF2);
break;
} else
intFromF1 = f1.readInt();
} else {
f3.writeInt(intFromF2);
if (f2.available() == 0 || f2Count++ >= segmentSize) {
f3.write(intFromF1);
break;
} else
intFromF2 = f2.readInt();
}
}

while (f1.available() > 0 && f1Count++ < segmentSize) {
f3.write(f1.readInt());
}

while (f2.available() > 0 && f2Count++ < segmentSize) {
f3.write(f2.readInt());
}
}

public static void displayFile(String fileName) {
try {
DataInputStream input = new DataInputStream(new FileInputStream(fileName));
for (int i = 0; i < 100; i++) {
System.out.print(input.readInt() + " ");
}
input.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  外部排序