下面代码功能 1. 生成100000个数据(generateFiles();),乱序,存储在d:/test/out.dat中。
2. 将生成的这么多个数据的一个文件的数据读出来,hash成128个小文件d:/test/1/go(i).txt。
3. 将128个小文件分别读出排序,然后输出到另外128个文件中d:/test/2/go(i).txt。
4. 将排好序的128个文件用多路归并-败者树的方法进行排序,结果打印并输出在d:/test/ans.dat中。
个人见解,有人有讨论,多路归并的k(非2的n次)路实现,但个人表示不太好实现,如果不够文件数,建议要么虚拟多路,要么减少路,以使之达到2的n次。
下面代码是128路归并。
概念:http://baike.baidu.com/view/7334038.htm?fr=aladdin
原理可参考:http://blog.chinaunix.net/uid-25324849-id-2182916.html
扫描多路归并实现:http://www.cnblogs.com/this-543273659/archive/2011/07/30/2122083.html
#include <iostream>
#include <algorithm>
#include <fstream>
#include <conio.h>
using namespace std;
char *mypath = "d:/test/out.dat";
const int k = 128;
const int MAXKEY = 1000000000;
fstream lastread[128];
// 生成一个100000个不同数据的文档,大小为1-100000
void generateFiles()
{
int a[10000];
int i;
for(i=0;i<10000;++i)
a[i] = i+1;
random_shuffle(a,a+10000);
ofstream out(mypath,ios::out|ios::binary|ios::app);
for(i=0;i<10000;++i)
out.write((char*)&a[i],sizeof(int));
out.close();
}
// 把文件读入,并hash成128个小文件
void rewritefiles()
{
int data;
ifstream in(mypath,ios::in|ios::binary);
fstream arr[128];
for(int i=0;i<128;++i)
{
char path[100];
sprintf_s(path,100,"d:/test/1/go%d.txt",i+1);
arr[i].open(path,ios::out|ios::binary|ios::in|ios::app);
arr[i].seekg(0);
if(!arr[i])
cout<<"openfile"<<i<<"error"<<endl;
}
while(in.read((char *)&data,sizeof(int)))
{
int id = (data + 64) % 128;
arr[id].write((char*)&data,sizeof(int));
}
in.close();
for(int i=0;i<128;++i)
arr[i].close();
}
// 对每个小文件内容排序后写入另外一个文件中
void sortEachFiles()
{
int tmp[1000],data;
fstream inout[128];
for(int i=0;i<128;++i){
char path[100];
int j=0;
sprintf_s(path,100,"d:/test/1/go%d.txt",i+1);
inout[i].open(path,ios::in|ios::binary|ios::app);
while(inout[i].read((char *)&data,sizeof(int)))
{
tmp[j++] = data;
}
inout[i].close();
sort(tmp,tmp+j);
sprintf_s(path,100,"d:/test/2/go%d.txt",i+1);
fstream test(path,ios::binary|ios::out);
for(int m=0;m<j;++m)
{
// cout<<tmp[m]<<endl;
test.write((char *)&tmp[m],sizeof(int));
}
test.close();
}
}
// 初始化多个文件输入流
void initial()
{
for(int i=0;i<128;++i){
char path[100];
sprintf_s(path,100,"d:/test/2/go%d.txt",i+1);
lastread[i].open(path,ios::in|ios::binary);
}
}
// 如果文件内容没有读完就读下一个数据,否则返回一个MAXKEY
int getnext(int i)
{
int data;
if(lastread[i].read((char *)&data,sizeof(int)))
return data;
else
return MAXKEY;
}
// 对败者树的一次调节,即把当前叶子节点,插入到ls中失败的地方,让这个地方的取胜节点,往上面继续跑
void Adjust(int *ls,int s,int *b)
{
int t = (s+k) /2; //在ls中父节点的数值(标记在b中的数值)
while( t>0 ){
if(b[s] > b[ls[t]]){
int temp = s;
s = ls[t];
ls[t] = temp;
}
t /= 2;
}
ls[0] = s;
}
// 对多个文件进行合并操作,输出打印以及写入文件
void M_merge(int *ls)
{
ofstream ans("d:/test/ans.dat",ios::binary|ios::out);
int b[k+1],i,q;
b[k] = -1;
for(i=0;i<k;++i){
b[i] = getnext(i);
ls[i] = k;
}
for(i=k-1;i>=0;--i)
Adjust(ls,i,b);
while(b[ls[0]] != MAXKEY){
q = ls[0];
ans.write((char *)&b[q],sizeof(int));
cout<<b[q]<<endl;
b[q] = getnext(q);
Adjust(ls,q,b);
}
ans.close();
}
// 测试某文件内容的函数
void printffile(char *path)
{
fstream cc(path,ios::out|ios::binary|ios::in);
int data;
while(cc.read((char*)&data,sizeof(int)))
{
cout<<data<<endl;
}
cc.close();
}
void closestream()
{
for(int i=0;i<128;++i)
lastread[i].close();
}
int main()
{
// generateFiles();
// rewritefiles();
// sortEachFiles();
initial();
int ls[129];
M_merge(ls);
// printffile("d:/test/2/go1.txt");
closestream();
getch();
return 0;
}