【数据结构】文件的归并排序

news2024/11/27 8:37:09

  

目录

1、归并排序引申出的问题

2、磁盘与文件的关系---包含与被包含的关系

3、思路:

4、代码实现 


1、归并排序引申出的问题

归并排序是最常用的外排序的方法(但归并排序既可进行内部排序也可进行外部排序),外排序就是在磁盘中的排序,不是在内存中。

文件中有10亿个数据,需要排序,怎么办?假设内存中最多只能放1000w个数据。

怎么弄?用磁盘来弄,因为磁盘我们可认为是无限大的,因为磁盘有几百个G。

补充知识(会就不用看):

2、磁盘与文件的关系---包含与被包含的关系

 磁盘、文件夹和文件三者之间存在包含与被包含的关系。磁盘存储的数据中包括文件夹和文件,文件夹中也可包含文件夹和文件,理解为文件夹是一个小型的磁盘,而文件就是具体的存储数据。磁盘是为了便于管理电脑中所有数据而划分出来的分区,文件夹是为了便于管理磁盘中数据文件而建立的,文件则是存储数据信息而存在的,所以管理区域不同(磁盘中虽可以直接保存文件,但当文件过多时不利于用户查找,故最好用文件夹将其归类存放),但这三者具备共同的存储数据功能。 

3、思路:

把10亿个数据读出来,因为文件中排序太慢(磁盘中和内存中的速度相差很多),故在内存中排,而内存中每次最多只能放1000w个数据,则分为100份,每份都在内存中排完再放入文件。归并是在文件中归并。(外排序尽量在内存中小段小段排好序,再用来归并,这样效率才高)

大文件平均分割为n份(具体多少份看实际情况),保证每份大小可以加载到内存,那就可把每个小文件加载到内存中,使用快排排成有序,再写回小文件。

总结:

1亿个数据不便于测试和写,我们这里假设用100个数据,分为10份(10个文件,每个文件10个数据)来处理:

整体思路:

1、排序:

把100个数据分为10份,每份10个数据,对于每一份先排序(这里我利用快排)然后保存到数组中,排完再把数组中10个数据写入第一个文件中,然后循环,直到10个文件写完了

2、归并:

因为文件内部有序了,所以两个文件才可归并。不采用两个两个挨着归并,因为会建很多文件(如下如①),我们采用下图中的②,两个文件归并完后的文件再和后一个文件归并

①、

 ②、

4、代码实现 

#include<stdio.h>
#include<stdlib.h>

//归并两个文件
void _MergeFile(const char*  file1, const char*  file2, const char*  mfile)
{//把两个小文件归并为一个文件(mfile),因为已知这两个小文件是有序的,所以才可以归并
	FILE* fout1 = fopen(file1, "r");
	if (fout1 == NULL)
	{
		printf("打开文件失败\n");
		exit(-1);
	}
	FILE* fout2 = fopen(file2, "r");
	if (fout2 == NULL)
	{
		printf("打开文件失败\n");
		exit(-1);
	}
	FILE* fin = fopen(mfile, "w");
	if (fin == NULL)
	{
		printf("打开文件失败\n");
		exit(-1);
	}

	int num1, num2;
	int ret1 = fscanf(fout1, "%d\n", &num1);//fscanf返回值是所读入的数据个数或EOF,即返回值为整形
	int ret2 = fscanf(fout2, "%d\n", &num2);
	while (ret1 != EOF && ret2 != EOF)
	{//如果两个中有一个文件读完了,则循环终止

		//谁小就先写入mfile文件中
		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);
		}
	}
	//看两个文件中哪个文件中还有数据,就写入fin文件中
	// 但下面的代码不行,假设上面ret1读到EOF了,ret2可能就是一个数
	// 然后你又fscanf读了一次放入num1(2)中,这就导致原来ret1和ret2
	// 中保存的数据丢失了,所以还要用ret1和ret2继续实现
	//while (fscanf(fout1, "%d\n", &num1) != EOF)
	//{//fscanf返回值为0时,表示未成功匹配到任何数据项
	返回值为-1时,表示在读取过程中出现了错误
	返回值为正整数:表示成功匹配并读取的数据项数
	//	fprintf(fin, "%d\n", num1);
	//}
	//while (fscanf(fout2, "%d\n", &num2) != EOF)
	//{
	//	fprintf(fin, "%d\n", num2);
	//}
	while (ret1 != EOF)
	{
		fprintf(fin, "%d\n", num1);
		ret1 = fscanf(fout1, "%d\n", &num1);
	}
	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;//切10份
	int a[10];//每份都10个数据
	int i = 0;
	int num = 0;
	char subfile[20];//文件名
	int filei = 1;//假设从第一个文件开始
	while (fscanf(fout, "%d\n", &num) != EOF)
	{
		if (i < n - 1)
		{//如果写为i<n,确实读了n(10)个数据,但是最后读完了还要一次while循环
		//fscanf又读了一次,放入num,可是此时直接开始排序了,排完i=0了,然后又while
		//循环一次,放入num中,可之前那个num你还没用,就又读了一个,导致数据丢失
		//故这里用i<n-1,先读n-1(9)个数据,然后走else把读到的num给a[i],然后排序完
		//i再置为0再完成下一个文件的,这里就符合了
			a[i++] = num;
		}
		else
		{	
			a[i] = num;
			//读满了10个数据
			QuickSort(a, 0, n - 1);//快速排序,自己写的函数,只要能排成升序即可
			sprintf(subfile, "%d", filei++);//输出文件名到subfile
			FILE* fin = fopen(subfile, "w");
			if (fin == NULL)
			{
				perror("fopen");
				exit(-1);
			}
			for (int i = 0; i < n; i++)
			{
				fprintf(fin,"%d\n", a[i]);
			}
			fclose(fin);

			i = 0;//i=0,以便写入下一个文件
		}
	}

	//利用互相归并到文件,实现整体有序
	char mfile[100] = "12";//归并出的文件
	char file1[100] = "1";
	char file2[100] = "2";
	//要归并n个文件
	for (int i = 2; i <= n; i++)
	{

		//读取file1和file2,进行归并出mfile
		_MergeFile(file1, file2, mfile);

		strcpy(file1, mfile);//将mfile文件名拷贝给file1,以便下一次的归并
		sprintf(file2, "%d", i + 1);//同时file2文件名向后一位
		sprintf(mfile, "%s%d", mfile, i + 1);//赋予新的文件名
	}

	fclose(fout);
}


int main()
{
	int a[6] = { 4,2,5,7,8,2 };
	
	MergeSortFile("sort.txt");
	return 0;
}

运行结果分析:

 首先在当前程序文件目录下创建"sort.txt"文件,并写入100个数据,一行一个,最后会产生以下文件,12345678910文件中的数据才是100个数据排好的状态

 

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

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

相关文章

LLaMA(Open and Efficient Foundation Language Models )论文解读(二)

此篇博客主题:LLAMA模型数据、训练时长、功耗及碳排放量 LLaMA: Open and Efficient Foundation Language Models paper https://arxiv.org/pdf/2302.13971v1.pdf 1 训练样本 Overall, our entire training dataset contains roughly 1.4T tokens after tokenization. For mo…

2023年Q2京东厨卫大电市场分析报告(京东运营数据分析)

随着新产品推广和消费需求升级&#xff0c;今年Q2&#xff0c;京东厨卫大电市场的销售额突破百亿&#xff0c;从同环比来看均呈增长趋势。百亿市场中&#xff0c;油烟机、电热水器、燃气热水器这三大品类占据较大份额&#xff0c;这一期&#xff0c;我们重点来看一下京东厨卫大…

怎么用Postman脚本中发送请求

Postman的Collection(集合)/Folder(集合的子文件夹)/Request(请求)都有Pre-request script和Tests两个脚本区域, 分别可以在发送请求前和请求后使用脚本(基于Javascript实现各种操作) 在遇到有依赖的接口时,比如需要登录或者需要从前一个接口的结果中获取参数时,我们往往需要在…

vscode 调试(linux )

一、配置程序运行依赖 1, 打开配置文件&#xff08;launch.json) (1) 从工具栏打开Run–>Add Configuration… &#xff08;2&#xff09;查看配置文件&#xff08;launch.json&#xff09; 2&#xff0c;添加配置 (1) 配置可执行程序&#xff08;program&#xff09;…

ceph存储的应用

ceph存储的应用 一&#xff1a;创建 CephFS 文件系统 MDS 接口1.服务端操作1&#xff09;在管理节点创建 mds 服务2&#xff09;查看各个节点的 mds 服务3&#xff09;创建存储池&#xff0c;启用 ceph 文件系统4&#xff09;查看mds状态&#xff0c;一个up&#xff0c;其余两个…

reggie优化01-缓存短信验证码和菜品数据

1、缓存短信验证码 1.1 Redis配置类RedisConfig 在config包下&#xff0c;创建Redis配置类RedisConfig&#xff1a; 纳入Git管理&#xff1a; package com.itheima.reggie.config;import org.springframework.cache.annotation.CachingConfigurerSupport; import org.sprin…

接口自动化测试框架unittest和pytest差异比较

前言 说到 Python 的单元测试框架&#xff0c;想必接触过 Python 的朋友脑袋里第一个想到的就是unittest。 的确&#xff0c;作为 Python 的标准库&#xff0c;它很优秀&#xff0c;并被广泛用于各个项目。但你知道吗&#xff1f;其实在 Python 众多项目中&#xff0c;主流的单…

【ROS机械臂入门教程】

首先声明一下&#xff0c;此项目是参考B站哈萨克斯坦UP的【ROS机械臂入门教程】&#xff0c;前期以复现【机械臂视觉抓取从理论到实战】 此内容为他研究生生涯的阶段性成果展示和技术分享&#xff0c;所有数据和代码均开源。所以鹏鹏我又特此来复现一下&#xff0c;我采用的硬件…

Redis源码篇 - Reactor设计模式 和 Redis Reactor设计模式

Reactor &#xff1a;反应器模式或者应答者模式&#xff0c;它是一种基于事件驱动的设计模式。拥有一个或者多个输入源&#xff0c;通过反应器分发给多个worker线程处理&#xff0c;实现并发场景下事件处理。 此图网上找的&#xff0c;画的很好&#xff1a;

中国新一代载人运载火箭“长征十号”发布,衍生型号积极研发中

我国新一代载人运载火箭“长征十号”已发布&#xff0c;主要用于将月面着陆器和登月飞船送入地月转移轨道。此外&#xff0c;“长征十号”还有一个衍生型号正在积极研发中。根据中国运载火箭技术研究院官方消息&#xff0c;近期&#xff0c;火箭院北京强度环境研究所圆满完成了…

SQlite3数据库相关相关命令

1&#xff09;系统命令 以 ‘.’ 开头 .help 帮助手册 .exit 退出 .table 查看当前数据库的有的表格名 .databases .schema 查看表的结构属性2&#xff09;sql语句 以 ;结尾 1. 创建表格 create table <table-name> (id integer, age integer, name char, score f…

夜深人静学32系列18——DMA+ADC单/多通道采集

夜深人静学32系列18——DMAADC单/多通道采集 DMA & ADC (理论篇)DMADMA框图DMA通道与外设对应表 ADC重要知识不同模式组合的作用 为什么要是用DMA ADC&#xff1f;DMA & ADC (实战篇)任务要求原理图CubeMX配置代码实现实验现象 很久没更新了&#xff0c;这次我们浅浅的…

MVSNet、PatchMatchNet环境配置、运行演示

文章目录 1 环境配置要求2 配置流程2.1 创建新环境mvs环境2.2 配置 PatchMatchNet环境3 程序运行演示1 环境配置要求 Ubuntu 18.04 python 3.7 , CUDA 10.1。 requirements.txt torch==1.4.0 torchvision==0.5.0 opencv-python numpy plyfile pillow tensorboard以上环境MV…

Docker 快速搞定 selenium grid 分布式测试

目录 前言&#xff1a; NO.1 搭环境 NO.2 写代码 NO.3 并发 感想 前言&#xff1a; Docker是一个流行的容器化平台&#xff0c;它可以帮助开发人员快速构建、部署和运行应用程序。Selenium Grid是一个用于分布式测试的工具&#xff0c;它可以并行执行多个测试用例&#xf…

做接口测试需要哪些技能、怎么做?

目录 1、什么是接口测试&#xff1f; 2、接口测试需要会什么&#xff1f; 3、如何学这些技能&#xff1f; 4、如何获取接口相关信息&#xff1f; 5、如何进行进行接口测试&#xff1f; 6、自动化接口测试 7、其他 1、什么是接口测试&#xff1f; 定义&#xff1a;测试系…

【ARM Coresight 系列文章 10 - ARM Coresight STM 介绍及使用】

文章目录 ARM System Trace MacrocellSTM FeaturesSTM 与 ETM/PTM的差异STM Master ARM System Trace Macrocell ARM 对STM 的解释是其支持高带宽的"仪器化输出"&#xff0c;仪器化输出其实也就是像 Cortex-M 系列中的 ITM 一样&#xff0c;通过将数据写入 STM 的 s…

(中等)LeetCode 328. 奇偶链表 Java

对于链表中有零个、一个、两个节点的情况&#xff0c;直接返回即可 对于链表的节点数大于两个的情况&#xff0c;需要讨论&#xff0c;看当前节点是第奇数个节点还是第偶数个节点 class Solution {public ListNode oddEvenList(ListNode head) {if (head null || head.next …

Android Glide onlyRetrieveFromCache downloadOnly submit ,kotlin

Android Glide onlyRetrieveFromCache downloadOnly submit ,kotlin Glide预加载&#xff0c;加载到磁盘或者内存缓存&#xff0c;然后加载的图片只从缓存&#xff08;磁盘缓存或者内存缓存&#xff09;中取。 private val imageFile File("/storage/emulated/0/DCIM/Ca…

百科创建必看攻略!人物百度百科怎么创建?5分钟教会你创建人物百度百科词条

百度人物百科是一个广受欢迎的在线百科平台&#xff0c;它为用户提供了一个便捷的方式来了解各种各样的人物信息。如果你有一个人物的详细资料&#xff0c;你可以通过创建一个百度人物百科页面来分享这些信息。 下面是分媒互动分享的创建百度人物百科页面的步骤以及需要注意的几…

ConfigMap 补充 和 Secret

对于上一篇文章我们分享了为什么要使用 ConfigMap &#xff0c;我们创建 ConfigMap 的时候可以传入单个或者多个键值对&#xff0c;也可以传入文件&#xff0c;还分享了如何简单的传入 ConfigMap 里面的数据作为环境变量 我们补充一下使用 ConfigMap 一次性传递多个条目吧 一…