//多路归并外排序的实现
//将一个保存在磁盘上的文件内的数据进行排序
//基本思路是:设文件共有m*n条记录, 内存中每次可以对m条记录进行排序
//则排序过程分两步:
//第一步:从磁盘中读入m条记录到内存; 在内存排序; 将排好序的数据写入新文件;
// 重复上述过程n次 共生成n个新文件
//第二步:分配一个文件指针数组 包含n个文件指针,分别指向n个新文件;
// 分配一个整数数组 大小为n 分别顺序读取各个文件的数据
// 分配一个布尔数组 大小为n 指示各个文件是否读完
// 将读入的整数数组中最小的值写入外存 并继续往后读取对应的文件 然后重复这一步 直到所有的文件都读完
这种算法思想常用于大文件排序,文件大小超出内存容量,可以每次读取内存容量的数据进行内存排序,然后进行归并
采用类似思想还可以解决很多海量数据处理的问题,当内存容量不足以一次处理时,通常都是先将大文件分为小文件,然后分而治之
关键程序段:
第一步
while(1) {
/*将数据读入内存,一次存满一数组*/
while(i!=mount && (fscanf(in,"%d",&a[i])!=EOF))i++;
/*内存内排序*/
qsort(a, 0, i-1);
/*将内存中排好的数据写到磁盘*/
while(j!=i)fprintf(out, "%d ",a[j++]);
if(i!=mount) break;
}
第二步
for(k=0;k<file_count;k++) {
/*打开所有k个文件*/
files[k] = fopen(tf_name,"r");
/*让一个k大的数组依次指向每个文件,并用一个k大的bool数组指示此文件有没有读完*/
if (fscanf(files[k], "%d ", &b[k]) == EOF) b_tag[k]=false;
}
while (true) {
min = b[0];
min_p = 0;
/*在k个文件的“当前数据”中找最小的*/
for (k=0;k<file_count;k++) {
if (b_tag[k]&&b[k]<min) {
min=b[k];
min_p = k;
}
}
if (min_p == 0 && !b_tag[0]) break;
/*写入文件*/
fprintf(out, "%d ", min);
/*然后对应的文件中的指针后移*/
if (fscanf(files[min_p], "%d ", &b[min_p])==EOF){
b_tag[min_p] = false;
}
}
全部源代码
///
#include <iostream>
using namespace std;
class ExternSort
{
public:
ExternSort(const char *in, const char *out, int m)
{
file_in = new char[strlen(in)+1];
strcpy(file_in, in);
file_out = new char[strlen(out)+1];
strcpy(file_out, out);
mount = m;
}
~ExternSort()
{
delete []file_in;
delete []file_out;
}
int sort()
{
FILE *in = NULL;
FILE *out = NULL;
FILE **files = NULL;
if (!(in = fopen(file_in, "r"))){
cout<<"open file error"<<endl;
}
int file_count = 0;
char tf_name[10];
int a[mount], k;
int *b = NULL;
bool *b_tag = NULL;
int min, min_p;
while(1) {
int i=0, j=0;
while(i!=mount && (fscanf(in,"%d",&a[i])!=EOF))i++;
qsort(a, 0, i-1);
sprintf(tf_name,"%d",file_count++);
out = fopen(tf_name, "w");
while(j!=i)fprintf(out, "%d ",a[j++]);
fclose(out);
if(i!=mount) break;
}
out = NULL;
files = new FILE*[file_count];
b = new int[file_count];
b_tag = new bool[file_count];
memset(files, 0, file_count);
memset(b, 0, file_count);
memset(b_tag, true, file_count);
for(k=0;k<file_count;k++) {
sprintf(tf_name, "%d", k);
files[k] = fopen(tf_name,"r");
if (fscanf(files[k], "%d ", &b[k]) == EOF) b_tag[k]=false;
}
out = fopen(file_out, "a");
while (true) {
min = b[0];
min_p = 0;
for (k=0;k<file_count;k++) {
if (b_tag[k]&&b[k]<min) {
min=b[k];
min_p = k;
}
}
if (min_p == 0 && !b_tag[0]) break;
fprintf(out, "%d ", min);
if (fscanf(files[min_p], "%d ", &b[min_p])==EOF){
b_tag[min_p] = false;
}
}
fclose(in);
fclose(out);
for(k=0;k<file_count;k++) fclose(files[k]);
for(k=0;k<file_count;k++) {
sprintf(tf_name, "%d", k);
remove(tf_name);
}
delete[] b;
delete[] b_tag;
delete[] files;
}
private:
char *file_in;
char *file_out;
int mount;
void qsort(int *a, int s, int e)
{
int i=s, j=e;
int temp = a[i];
if (i<j) {
while (i<j) {
while (i<j&&a[j]>=temp)j--;
a[i] = a[j];
while (i<j&&a[i]<=temp)i++;
a[j] = a[i];
}
a[i] = temp;
qsort(a, s, i-1);
qsort(a, i+1, e);
}
}
};
int main(int argc, char *args[])
{
FILE *f = fopen("in", "w");
for(unsigned int i=0; i<10000000;i++) fprintf(f, "%d ", rand()%10000);
fclose(f);
ExternSort e = ExternSort("in", "out",100000 );
e.sort();
}