大数据-多路归并-败者树-文件流

本文介绍了一种处理大规模数据的排序算法,该算法通过生成大量数据并将其散列到多个小文件中,随后对这些小文件进行排序,最后采用多路归并-败者树的方式完成最终排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面代码功能 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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值