利用画图以及代码分析详细解读外排序的实现过程

news2024/9/29 9:35:56

外排序的实现

  • 思想
  • 代码分析
  • 完整代码

如果有海量数据需要排序,而在内存中放不下这么多数据,因此就不能使用内排序(直接插入排序,希尔排序,堆排序,快速排序,归并排序等等)。关于想了解这些内排序的请看这里各种排序的实现,所以我们只能使用外排序,来把我们海量数据排好序,

思想

外排序,我们需要采用归并排序的思想来实现这个过程。
在这里插入图片描述

因此我们最终思想是这样的
在这里插入图片描述

代码分析

要学会写外排序的代码,需要把文件学好,想了解文件的请看这里文件

假设文件里有100个数据
生成1-100个随机数放在文件里

#define N 100

void CreteartFile(const char* filename)
{
	srand((unsigned int)time(NULL));

	//生成一个随机数1-100的文件
	FILE* pf = fopen(filename, "w");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}


	for (int i = 0; i < N; ++i)
	{
		fprintf(pf, "%d ", rand() % 100 + 1);
	}

	fclose(pf);

}

int  main()
{
	
	
	const char* filename = "Sort.txt";
	CreteartFile(filename);
	//外排序
	MerSortFile(filename);

	return 0;
}

把文件平均分成若干个有序的小文件

我们有一个100个数的文件
把这个文件平均分成10个小文件,每个小文件放10个数。
为了使这些小文件的数据有序,因此我们在大文件里取出数据,放在数组a中,只要数组a里的数据达到10个。就对数组a使用快排(假设内存可以一次放得下这么数据),直到取完文件中的数据。

//外排序
void MerSortFile(const char* filename)
{
	//取数据,把一个文件分成若干个有序的小文件
	FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		return;
	}
	int a[10] = { 0 };
	int value = 0;
	int i = 0;
	int n = 10;
	//存放小文件名称
	char fsubename[10] = { 0 };
	int fnumeber = 0;

	//从文件中取出数据
	while (fscanf(fout, "%d", &value) != EOF)
	{
		//一个小文件放10个数据
		if (i < n-1)
		{
			a[i++] = value;
		}
		else
		{
		//这里是特殊处理,下面画图有解释
			a[i] = value;

			//对a数组排序
			QuickSort(a, 0, n - 1);

			//创建小文件,并将a写到小文件里
			sprintf(fsubename, "%d.txt", ++fnumeber);

			FILE* fin = fopen(fsubename, "w");
			if (fin == NULL)
			{
				perror("fopen fail");
				return;
			}
			//写数据
			for (int i = 0; i < n; ++i)
			{
				fprintf(fin, "%d ", a[i]);
			}
			fclose(fin);
			i = 0;
		}
	}


	fclose(fout);
}

在这里插入图片描述
两两归并小文件,直到归并成一个文件

//外排序
void MerSortFile(const char* filename)
{
	//取数据,把一个文件分成若干个有序的小文件
	FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		return;
	}
	int a[10] = { 0 };
	int value = 0;
	int i = 0;
	int n = 10;
	char fsubename[10] = { 0 };
	int fnumeber = 0;

	while (fscanf(fout, "%d", &value) != EOF)
	{
		//一个小文件放10个数据
		if (i < n-1)
		{
			a[i++] = value;
		}
		else
		{
			a[i] = value;

			//对a数组排序
			QuickSort(a, 0, n - 1);

			//创建小文件,并将a写到小文件里
			sprintf(fsubename, "%d.txt", ++fnumeber);

			FILE* fin = fopen(fsubename, "w");
			if (fin == NULL)
			{
				perror("fopen fail");
				return;
			}
			//写数据
			for (int i = 0; i < n; ++i)
			{
				fprintf(fin, "%d ", a[i]);
			}
			fclose(fin);
			i = 0;
		}
	}

	//归并小文件,直到整体归成一个有序的完整文件
	//这一块逻辑看下图分析
	char mfile[20] = "12";
	char file1[20] = "1.txt";
	char file2[20] = { 0 };
	for (int i = 2; i <= n; ++i)
	{
		sprintf(file2, "%d.txt", i);
		_MergerFile(mfile, file1, file2);
		//迭代,file1存储mfile名
		strcpy(file1, mfile);
		//mfile存储下一次两个文件要归并在一起的文件名
		sprintf(mfile, "%s%d", mfile, i+1);
	}

	fclose(fout);
}

在这里插入图片描述
两个小文件归并过程

void _MergerFile(const char* mfile,const char* file1,const char* file2)
{
	FILE* fin = fopen(mfile, "w");
	if (fin == NULL)
	{
		perror("fopen fail");
		return;
	}

	FILE* fout1 = fopen(file1, "r");
	if (fout1 == NULL)
	{
		perror("fopen fail");
		return;
	}

	FILE* fout2 = fopen(file2, "r");
	if (fout2 == NULL)
	{
		perror("fopen fail");
		return;
	}
	int num1 = 0;
	int num2 = 0;
//这里也是对文件指针的特殊处理,看下图
	int ret1 = fscanf(fout1, "%d", &num1);
	int ret2 = fscanf(fout2, "%d", &num2);

	while (ret1 != EOF && ret2 != EOF)
	{
		if (num1 < num2)
		{
			fprintf(fin, "%d ", num1);
			ret1= fscanf(fout1, "%d", &num1);
		}
		else
		{
			fprintf(fin, "%d ", num2);
			ret2 = fscanf(fout2, "%d", &num2);

		}
	}

	while (ret1 != EOF)
	{
		fprintf(fin, "%d ", num1);
		ret1 = fscanf(fout1, "%d", &num1);
	}

	while (ret2 != EOF)
	{
		fprintf(fin, "%d ", num2);
		ret2 = fscanf(fout2, "%d", &num2);
	}

	fclose(fin);
	fclose(fout1);
	fclose(fout2);


}

在这里插入图片描述

完整代码

//合并小文件
void _MergerFile(const char* mfile,const char* file1,const char* file2)
{
	FILE* fin = fopen(mfile, "w");
	if (fin == NULL)
	{
		perror("fopen fail");
		return;
	}

	FILE* fout1 = fopen(file1, "r");
	if (fout1 == NULL)
	{
		perror("fopen fail");
		return;
	}

	FILE* fout2 = fopen(file2, "r");
	if (fout2 == NULL)
	{
		perror("fopen fail");
		return;
	}
	int num1 = 0;
	int num2 = 0;

	int ret1 = fscanf(fout1, "%d", &num1);
	int ret2 = fscanf(fout2, "%d", &num2);

	while (ret1 != EOF && ret2 != EOF)
	{
		if (num1 < num2)
		{
			fprintf(fin, "%d ", num1);
			ret1= fscanf(fout1, "%d", &num1);
		}
		else
		{
			fprintf(fin, "%d ", num2);
			ret2 = fscanf(fout2, "%d", &num2);

		}
	}

	while (ret1 != EOF)
	{
		fprintf(fin, "%d ", num1);
		ret1 = fscanf(fout1, "%d", &num1);
	}

	while (ret2 != EOF)
	{
		fprintf(fin, "%d ", num2);
		ret2 = fscanf(fout2, "%d", &num2);
	}

	fclose(fin);
	fclose(fout1);
	fclose(fout2);


}

//外排序
void MerSortFile(const char* filename)
{
	//取数据,把一个文件分成若干个有序的小文件
	FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		return;
	}
	int a[10] = { 0 };
	int value = 0;
	int i = 0;
	int n = 10;
	char fsubename[10] = { 0 };
	int fnumeber = 0;

	while (fscanf(fout, "%d", &value) != EOF)
	{
		//一个小文件放10个数据
		if (i < n-1)
		{
			a[i++] = value;
		}
		else
		{
			a[i] = value;

			//对a数组排序
			QuickSort(a, 0, n - 1);

			//创建小文件,并将a写到小文件里
			sprintf(fsubename, "%d.txt", ++fnumeber);

			FILE* fin = fopen(fsubename, "w");
			if (fin == NULL)
			{
				perror("fopen fail");
				return;
			}
			//写数据
			for (int i = 0; i < n; ++i)
			{
				fprintf(fin, "%d ", a[i]);
			}
			fclose(fin);
			i = 0;
		}
	}

	//归并小文件,直到整体归成一个有序的完整文件
	char mfile[20] = "12";
	char file1[20] = "1.txt";
	char file2[20] = { 0 };
	for (int i = 2; i <= n; ++i)
	{
		sprintf(file2, "%d.txt", i);
		_MergerFile(mfile, file1, file2);
		strcpy(file1, mfile);
		sprintf(mfile, "%s%d", mfile, i+1);
	}

	fclose(fout);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/586540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java利用JOL工具分析对象分布

对象的组成 对象头[Header] Markword&#xff1a;存储对象自身运行时数据如hashcode、gc分代年龄等&#xff0c;64位系统总共占用8个字节&#xff0c;关于Markword详细内存分布如下 类型指针&#xff1a;对象指向类元数据地址的指针&#xff0c;jdk8默认开启指针压缩&#xff…

算法基础学习笔记——⑫最小生成树\二分图\质数\约数

✨博主&#xff1a;命运之光 ✨专栏&#xff1a;算法基础学习 目录 ✨最小生成树 &#x1f353;朴素Prim &#x1f353;Kruskal算法 ✨二分图 &#x1f353;匈牙利算法 ✨质数 &#x1f353;&#xff08;1&#xff09;质数的判定——试除法 &#x1f353;&#xff08;2&…

简单认识OSI(计算机网络分层)七层模型

前言 学校上课讲的太笼统啥也不是&#xff0c;自己学的太玄学似懂非懂突然在看到了一篇公众文文章。文章从初始到现在&#xff0c;步步为营的遇到一个解决一个前人的问题&#xff0c;有了细致入微的讲述&#xff0c;把之前学的死东西都连起来了。 如果让你来设计网络https://m…

chatgpt赋能python:Python取余数:介绍和实际应用

Python取余数&#xff1a;介绍和实际应用 Python是一种高级编程语言&#xff0c;其灵活性和多功能性使其成为开发者的首选之一。在Python中&#xff0c;取余数是常见的数学运算之一&#xff0c;这个操作在编写程序时非常有用。在本文中&#xff0c;我们将介绍Python中的取余数…

chatgpt赋能python:Python中单行输出的使用方法

Python中单行输出的使用方法 Python是广泛使用的高级编程语言之一&#xff0c;具有易于学习、可读性强和简单易用等优点。在Python编程中&#xff0c;我们经常需要输出文本内容&#xff0c;而Python中单行输出便是一个非常重要的功能。 什么是单行输出 单行输出是指将多个元…

TDengine 深入解析缓存技术

TDengine是一款高性能的物联网大数据平台。为了高效处理时序数据&#xff0c;TDengine中大量用到了缓存技术&#xff0c;自己实现了哈希表、缓存池等技术。本文会为大家讲解TDengine中用到的这些缓存技术。 首先会介绍一下什么是缓存&#xff0c;常用的缓存技术&#xff0c;最后…

想知道怎么翻译多个文本?我教你三个好方法吧

随着电子商务的全球化发展&#xff0c;越来越多的企业意识到将产品推向全球市场的重要性。在全球市场中&#xff0c;各种语言和文化的消费者都存在着巨大的潜在需求。为了吸引和服务这些不同语言的客户&#xff0c;企业需要采取一系列的措施&#xff0c;其中翻译是至关重要的一…

科技发展的那些事儿

近30年来&#xff0c;科技发展取得了惊人的成就&#xff0c;涉及范围广泛&#xff0c;包括计算机科学、通讯技术、生物医学、能源等多个领域。本文将列举近30年来科技发展的重要事件&#xff0c;并探讨这些事件对我们的生活、工作和社会产生的影响。 1991年&#xff0c;Linux操…

chatgpt赋能python:Python中可以用八进制表示整数吗?

Python中可以用八进制表示整数吗&#xff1f; Python是一种流行的动态编程语言&#xff0c;它支持许多整数表示方法。八进制是一种表示整数的方法&#xff0c;那么Python中可以使用八进制表示整数吗&#xff1f;本文将探讨这个问题。 什么是八进制&#xff1f; 在计算机科学…

基于SSM的服装设计供需系统设计与实现

摘 要&#xff1a;作为服装设计的重要形式之一&#xff0c;服装具有显著的审美性&#xff0c;是人类情感表达不可忽视的代表形态。但在新时期背景下&#xff0c;随着服装设计的进一步优化&#xff0c;服装设计创新融合强度也随之增强。本文就服装设计供需系统进行深入探究。 服…

chatgpt赋能python:如何在Python中去掉逗号

如何在Python中去掉逗号 在Python编程中&#xff0c;逗号是一个非常常见的符号&#xff0c;它通常用于分隔多个变量或值。然而&#xff0c;有时候我们需要从文本中去掉逗号&#xff0c;以便更好地处理数据。那么在Python中&#xff0c;如何去掉逗号呢&#xff1f;接下来&#…

华为OD机试真题B卷 Java 实现【停车场车辆统计】,附详细解题思路

一、题目描述 特定大小的停车场&#xff0c;数组cars[]表示&#xff0c;其中1表示有车&#xff0c;0表示没车。 车辆大小不一&#xff0c;小车占一个车位&#xff08;长度1&#xff09;&#xff0c;货车占两个车位&#xff08;长度2&#xff09;&#xff0c;卡车占三个车位&a…

idea使用Alibaba Cloud Toolkit插件远程操作Docker

idea使用Alibaba Cloud Toolkit插件远程操作Docker 前言 从github下载的开源项目源码&#xff0c;你基本上都能在项目根目录下发现会有个Dockerfile文件&#xff0c;Dockerfile文件是记录构建docker容器的构建命令&#xff0c;用途&#xff1a;一般用来将本地的jar包远程传输到…

内存对齐原则

struct &#xff08;1&#xff09;结构体第一个数据成员放在offset为0的地方&#xff0c;后面每个成员相对于结构体首地址的偏移量&#xff08;offset&#xff09;都是成员大小&#xff08;该变量类型所占字节&#xff09;的整数倍&#xff0c;如有需要编译器会在成员之间加上填…

中国人工智能学会主办!真实AIGC业务数据驱动,欢迎全球开发者参加

近期&#xff0c;由百度商业联合中国人工智能学会举办、NVIDIA提供战略支持&#xff0c;百度飞桨承办的“百度商业AI技术创新大赛”正式启动&#xff0c;启动会现场&#xff0c;中国工程院院士、中国人工智能学会理事长、清华大学信息科学技术学院院长戴琼海院士通过视频方式对…

chatgpt赋能python:在Python中一行书写两条语句:提高代码效率的好策略

在Python中一行书写两条语句&#xff1a;提高代码效率的好策略 从一开始Python就是因为简单易用、快速开发、名字有趣等因素而受到开发者的喜爱。当然&#xff0c;解释型语言也是Python深受欢迎的原因之一&#xff0c;你可以在Linux、Windows、Mac等各种平台上运行Python脚本&…

基于SSM的图书借阅管理系统

1.项目介绍 本项目是一款基于SpringSpring MVCMybatis的图书借阅管理系统&#xff0c;主要针对计算机相关主页的正在做课程设计的学生与需要项目实战学习、练习的Java学生人群。 该系统基于B/S架构&#xff0c;采用SpringSpring MVCMybatis框架技术&#xff0c;并结合主流的轻…

一起了解AJAX

注册账号的时候账号不能重复&#xff0c;通过AJAX实现实时验证当前注册的账号是否存在。 1.1register.jsp. 1.2HomeRegisterServlet. 2.JSON概述. 2.1何为JSON. JSON即 JavaScript Object Notation &#xff08;js对象标记&#xff09; ,是一种轻量级的数据交换格式&#xf…

Eclipse教程 Ⅷ

Eclipse Debug 配置 创建和使用 Debug 配置 Eclipse Debug 配置类似于运行配置但它是用于在调试模式下开启应用。 打开 Debug 配置对话框步骤为&#xff1a;Run > Debug Configurations 。 从左侧列表中选择 "Java Application" 选项来选择要调试的 Java 代码。…

使用KubeSphere3.3在Ubuntu20.04的Kubernetes1.24上部署Word Press

使用KubeSphere3.3在Ubuntu20.04的Kubernetes1.24上部署Word Press 前言 之前已经部署了KubeSphere和K8S的基础环境&#xff1a;https://lizhiyong.blog.csdn.net/article/details/126236516 部署了大数据统一文件编排层Alluxio&#xff1a;https://lizhiyong.blog.csdn.net…