当前位置: 首页 > news >正文

排序扩展-文件递归排序(外排序)

外排序是能够处理极大量数据的排序算法,简单来说,外排序处理的数据就是不能一次性装入内存,只能放在读写较慢的外存储器上(一般是硬盘上),外排序通常采用的是一种“排序-递归”的策略。在排序阶段,先读入能放在内存中的数据量,将排序输出到一个临时文件,依次进行,将待排序数据组织为多个有序的临时文件,然后在归并阶段将这些临时文件组合为一个大的有序文件,即排序结果。由于归并排序不需要随机访问数据,只需要依次按序列读取数据,所以归并排序不仅使内排序还是外排序。

上面一段文字我们基本上没看懂它在说什么,用普通的话来说,就是在平时的工作中我们基本上是有很多的数据,我们需要排序,如果用平时的排序算法会由于数据存放不下而导致无法解决,这时我们就需要借助文件来进行排序。

基本思路:(1)读取n个值排序后写到file1,再读取n个值排序后写到file2;(2)file1和file2利用归并排序的思想,依次读取比较,取小的尾插到mfile,mfile归并为有序文件;(3)将file1和file2删掉,mfile重命名为file1;(4)再读取n个数据排序后写入到file2;(5)继续走file1和file2归并,重复步骤2。直至没有数据。

我们需要先有一个创建数据的函数,开始我们让数据量减少一点,100000个数据我们每一次读取10000个数据进行排序,开始生成的数据放入到data.txt中,然后再和我们之前的想法进行排序、归并等操作,所以最终代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include<stdbool.h>
#include<stddef.h>//NULL
#include<time.h>
//数据总个数
#define N 100000
//每次读取的数据个数
#define m N/10
//创建n个随机数写到文件中
void CreateNDate()
{
	//造数据
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		fclose(fin);
		return;
	}
	for (int i = 0; i < N; ++i)
	{
		//生成随机数
		int x = rand() % 30000;
		//把数据按照一行一个的方式写入到文件中
		fprintf(fin, "%d\n", x);
	}
	//记得关闭文件
	fclose(fin);
}
//排序
int compare(const void* a, const void* b)
{
	return (*(int*)a - *(int*)b);
}
//读取m个数据排序
int ReadNDataSort(FILE* fout, const char* file1)
{
	FILE* fin = fopen(file1, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		fclose(fin);
		return 0;
	}
	int x = 0;
	int* a = (int*)malloc(sizeof(int) * m);
	if (a == NULL)
	{
		perror("malloc error");
		return 0;
	}
	//计数(看读取的数据是否到m个
	int j = 0;
	//从fout(data.txt)中读取m个数据
	for (int i = 0; i < m; i++)
	{
		//可能读到文件结尾了
		//所以不能这样写
		//fscanf(fout, "%d", &x);
		if (fscanf(fout, "%d", &x) == EOF)
		{
			break;
		}
		a[j++] = x;
	}
	if (j == 0)
	{
		free(a);
		a = NULL;  
		return 0;
	}
	//排序
	// 我们不确定是否有m个数据在文件里面,所以我们要把这个m改为j
	//qsort(a, m, sizeof(int), compare);
	qsort(a, j , sizeof(int), compare);
	//写回file1文件
	for (int i = 0; i < j; i++)
	{
		fprintf(fin, "%d\n", a[i]);
	}
	free(a);
	a = NULL;
	return j;
}
//把file1、file2归并到mfile中
void MergeFile(const char* file1, const char* file2, const char* mfile)
{
	FILE* fout1 = fopen(file1, "r");
	if (fout1 == NULL)
	{
		perror("file1 open error");
		return;
	}
	FILE* fout2 = fopen(file2, "r");
	if (fout2 == NULL)
	{
		perror("file2 open error");
		return;
	}
	FILE* fout3 = fopen(mfile, "w");
	if (fout3 == NULL)
	{
		perror("mfile open error");
		return;
	}
	//归并
	int x1 = 0;
	int x2 = 0;
	int ret1 = 0;
	int ret2 = 0;
	ret1 = fscanf(fout1, "%d", &x1);
	ret2 = fscanf(fout2, "%d", &x2);
	while (ret1 != EOF && ret2 != EOF)
	{
		if (x1 < x2)
		{
			fprintf(fout3, "%d\n", x1);
			ret1 = fscanf(fout1, "%d", &x1);
		}
		else
		{
			fprintf(fout3, "%d\n", x2);
			ret2 = fscanf(fout2, "%d", &x2);
		}
	}
	while (ret1 != EOF)
	{
		fprintf(fout3, "%d\n", x1);
		ret1 = fscanf(fout1, "%d", &x1);
	}
	while (ret2 != EOF)
	{
		fprintf(fout3, "%d\n", x2);
		ret2 = fscanf(fout2, "%d", &x2);
	}
	fclose(fout1);
	fclose(fout2);
	fclose(fout3);
}
int main()
{
	//造数据
	CreateNDate();
	const char* file1 = "file1.txt";
	const char* file2 = "file2.txt";
	const char* mfile = "mfile.txt";
	//打开文件
	FILE* fout = fopen("data.txt", "r");
	if (fout == NULL)
	{
		perror("fopen error");
		return -1;
	}
	//先进行排序,保证三个文件都不为空
	ReadNDataSort(fout, file1);
	ReadNDataSort(fout, file2);
	while (1)
	{
		//归并
		MergeFile(file1, file2, mfile);
		//删除file1、file2
		remove(file1);
		remove(file2);
		//重命名
		rename(mfile, file1);
		//再读文件入file2
		//可能读取不完全
		if (ReadNDataSort(fout, file2) == 0)
		{
			break;
		}
	}
	fclose(fout);
	return 0;
}

生成随机数的方式可以改为rand()+i,在我电脑上运行不出来结果,但是我看了很久都觉得代码无误,所以发出来了,最终如果生成成功的话后面你直接到这个代码的文件中去查看就可以了。

这就是全部的结果了,代码的运行结果我就没办法提供了,因为这个不是必须要掌握的,代码和结果不重要,只要知道如何实现的就可以了。

下一节将开始C++的学习了,如果感兴趣的可以继续学习哦,如果方向不一样去学习Java或者Python的也祝你们能更上一层楼吧!

相关文章:

  • [ERROR] Some problems were encountered while processing the POMs
  • 鸿蒙开发_ARKTS快速入门_语法说明_组件声明_组件手册查看---纯血鸿蒙HarmonyOS5.0工作笔记010
  • 1631. 最小体力消耗路径
  • Quartz 数据持久化 接入MySQL数据库 数据不丢失 数据入库
  • 人工智能通识速览(Part4. 评估指标)
  • Android WiFi协议之P2P介绍与实践
  • git功能点管理
  • Redis 与 MongoDB 对比分析
  • Stable Diffusion XL、SD3 与 Flux 模型常用优化器总结
  • 【群晖】挂载小雅alist到AList网盘中
  • Android Automotive车载系统面试题及参考答案
  • Swift语言的云存储
  • 11231231
  • 轨检探伤专用一体机平板电脑:为铁路安全保驾护航
  • docker的几种网络模式
  • 从搜索丝滑过渡到动态规划的学习指南
  • 数据库50个练习
  • 各开源协议一览
  • js前端对时间进行格式处理
  • 数据结构与算法-数学-基础数学算法(筛质数,最大公约数,最小公倍数,质因数算法,快速幂,乘法逆元,欧拉函数)
  • 上海将完善隔代照料支持措施:建设老幼共享设施、提高科学育儿指导力度
  • 4月22城新房价格上涨:上海一二手房价环比均上涨,核心城市土地热带动市场热度提升
  • 专访|金七猫奖得主:以非遗为舟,在现实题材中疗愈与成长
  • 海南乐城管理局原局长贾宁已赴省政协工作,曾从河南跨省任职
  • 从良渚到三星堆:一江水串起了5000年的文明对话
  • 芬兰直升机相撞坠毁事故中五名人员全部遇难