文件排序 (拓展)

举报
跳动的bit 发表于 2022/06/09 07:29:03 2022/06/09
【摘要】 ⚠ 注意  小文件排序是没有意义的,当然我们这里只是模拟,所以给 100 个数据🔑 核心思想 🔑  磁盘的读取速度相比内存差距非常大,所以我们不可能像在内存中两两归并。正确的归并方法是大文件平均分割成 N 份,保证每份大小都可以加载到内存,那么就可以把每个小文件加载到内存中,使用快排排序,再写回小文件,这时就达到文件中归并的先决条件🧿 实现代码 :void _MergeFile(con...

⚠ 注意

  小文件排序是没有意义的,当然我们这里只是模拟,所以给 100 个数据
在这里插入图片描述

🔑 核心思想 🔑

  磁盘的读取速度相比内存差距非常大,所以我们不可能像在内存中两两归并。正确的归并方法是大文件平均分割成 N 份,保证每份大小都可以加载到内存,那么就可以把每个小文件加载到内存中,使用快排排序,再写回小文件,这时就达到文件中归并的先决条件

在这里插入图片描述

🧿 实现代码 :

void _MergeFile(const char* File1, const char* File2, const char* mFile)
{
	//读文件1
	FILE* fout1 = fopen(File1, "r");
	if (fout1 == NULL)
	{
		printf("打开文件失败\n");
		exit(-1);
	}
	//读文件2
	FILE* fout2 = fopen(File2, "r");
	if (fout2 == NULL)
	{
		printf("打开文件失败\n");
		exit(-1);
	}
	//写文件3,把文件1和文件2写到文件3里
	FILE* fin = fopen(mFile, "w");
	if (fin == NULL)
	{
		printf("打开文件失败\n");
		exit(-1);
	}
	int num1, num2;
	//对于内存中没有问题,但是磁盘就有问题了。不管num1和num2谁小谁大,只要读了fout1和fout2它们都会往后走
	/*while (fscanf(fout1, "%d\n", &num1) != EOF 
		&& fscanf(fout2, "%d\n", &num2) != EOF)
	{
		if (num1 < num2)
			fprintf(fin, "%d\n", num1);
		else
			fprintf(fin, "%d\n", num2);
	}*/
	int ret1 = fscanf(fout1, "%d\n", &num1);
	int ret2 = fscanf(fout2, "%d\n", &num2);
	//下面保证了谁读谁走;fout1和fout2都不为空再比较
	while (ret1 != EOF && ret2 != EOF)
	{
		if (num1 < num2)
		{
			fprintf(fin, "%d\n", num1);
			ret1 = fscanf(fout1, "%d\n", &num1);//更新字符
		}
		else
		{
			fprintf(fin, "%d\n", num2);
			ret2 = fscanf(fout2, "%d\n", &num2); //更新字符
		}
	}
	/*注意这样会导致少写一个数据
		//fout2完了,写剩下的fout1
	while (fscanf(fout1, "%d\n", &num1) != EOF)
	{
		fprintf(fin, "%d\n", num1);
	}
		//fout1完了,写剩下的fout2
	while (fscanf(fout2, "%d\n", &num2) != EOF)
	{
		fprintf(fin, "%d\n", num2);
	}*/

	//fout2完了,写剩下的fout1
	while (ret1 != EOF)
	{
		fprintf(fin, "%d\n", num1);
		ret1 = fscanf(fout1, "%d\n", &num1);//更新字符
	}
	//fout1完了,写剩下的fout2
	while (ret2 != EOF)
	{
		fprintf(fin, "%d\n", num2);
		ret2 = fscanf(fout2, "%d\n", &num2); //更新字符
	}
	//关闭文件 
	fclose(fout1);
	fclose(fout2);
	fclose(fin);
}
void MergeSortFile(const char* file)
{
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		printf("打开文件失败\n");
		exit(-1);
	}
	int n = 10;
	int a[10];
	int i = 0;
	int num = 0;
	char subfile[20];
	int filei = 1;
	memset(a, 0, sizeof(int) * n);
	//从fout文件流里读,直至EOF
	while (fscanf(fout, "%d\n", &num) != EOF)
	{
		//每次循环读10个数据放在内存中(if里先放9个,else再放最后一个)
		if (i < n - 1)
		{
			a[i++] = num;
		}
		else
		{
			a[i] = num;
			//快排10个数据
			QuickSort(a, 0, n - 1);
			//生成文件名sub_sort1/2/3...
			sprintf(subfile, "%d", filei++);
			//写文件,subfile里存储生成的文件名
			FILE* fin = fopen(subfile, "w");
			if (fin == NULL)
			{
				printf("打开文件失败\n");
				exit(-1);
			}
			//写回小文件
			for (int i = 0; i < n; i++)
			{
				fprintf(fin, "%d\n", a[i]);
			}
			//关闭文件
			fclose(fin);
			//重置i
			i = 0;
			memset(a, 0, sizeof(int) * n);
		}
	}
	//互相归并到文件,实现整体有序
	char mFile[100] = "12";
	char File1[100] = "1";
	char File2[100] = "2";
	for (i = 2; i <= n; i++)
	{
		//读取File1和File2,归并出mFile
		_MergeFile(File1, File2, mFile);
		//拷贝迭代File1的文件名12/123/1234...
		strcpy(File1, mFile);
		//循环迭代File2的文件名3/4/5...
		sprintf(File2, "%d", i + 1);
		//循环迭代mFile的文件名123/1234/12345...
		sprintf(mFile, "%s%d",mFile, i + 1);
	}
	//关闭文件
	fclose(fout);
}
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。