(排序10)归并排序的外排序应用(文件排序)
TIPS
- 在一些文件操作函数当中,fputc与fgetc这两个函数都是针对字符的,如果说你需要往文件里面去放入整形啊等等,不是字符的类型,这时候就用fprintf,fscanf在参数里面数据类型控制一下就可以。但是话说回来,数据文件的话分为文本文件与二进制文件,文件里面的信息唯有二进制信息或者字符ASCII码,然后当你点开文件解析出来的时候都是强制解析成字符的。
- 对于C文件操作我还是想再补充几点:首先对于这两个函数fgetc,fputc他们针对的都是字符,比如说可以从内存当中往文件(以文件作为外部输出设备的例子)当中去放字符,也可以从文件当中往内存里面读出来一个字符,但无论如何,他针对的数据类型只有字符;
- 然后对于这两个函数fgets与fputs,他们针对的是一行字符串的输入与输出,这边尤其要注意在文件当中每一行字符串的末尾都是默认带有一个换行符\n,这个换行符的话也是需要计数的(参照fgets的参数),并且如果说条件允许也是会被拷贝到内存当中,并且文件指针一旦碰到了这个换行符,它也会换行;
- 对于fprintf, fscanf这两个函数来说的话,他们针对的是格式化字符串的输入输出,并且最大的优势与亮点就是说他们的类型很是自由,比如说我想往文件里面放入一个数字,然后我假设要从文件里面过一会儿读出这个数字重新到内存里面来,这时候就不好用fgetc,fputc。因为那两个的话是针对于字符的,这时候就用fprintf,fscanf加%d格式化非常nice。
- 最后对于这两个函数sscanf,sprintf来说,这两个函数的功能分别是从字符串当中去抠东西下来放到变量当中,粘连一些东西或者自己添油加醋一些合成一个新字符串。


归并排序的外排序(文件排序)
- 文件排序的话,主要是针对大文件,如果你针对小文件的话就没有意义了。但这边总不能真正的给500个g的数据吧,我们这边就模拟一下
- 现在假设有海量的排序数据,那么他这个数据肯定是在文件当中,在磁盘当中,因为磁盘相对于内存大太多了。然后如果我们要对这些数据进行排序的话,不能把他们全部一下子加载到内存里面,因为内存没有这么大
- 这时候我们只能用归并排序的思想,归并排序就是说比如说有两段有序的数据,这一段是有序的,那一段也是有序的。然后我们就开一个新的地方,然后每次取小的下来给他放到新的地方里面,就这样把两个有序区间给他归并到一个有序区间。好好去想一想归并的四个生动表述过程。

- 归并排序的话,既可以把它看成内排序,它也可以搞成外排序。但无论如何他都具有O(N)的空间复杂度,所以说是蛮消耗存储空间的。所以说在内排序当中,它跟快速排序相比的话逊一点,内排序综合快排取胜
- 然后现在当数据在文件当中的话,前面的那些快的排序:堆排啊,快排啊都不好弄了,堆排与快排的话都需要随机访问这个大前提,像数组的话很友好,能够支持随机访问,但文件的话就不能进行随机访问了,就算你可以去移动文件指针那也非常非常慢,磁盘的速度相比较于内存而言慢太多了,差异在几百几千倍。所以外排用归并。
- 但在归并的过程当中,如果说你用递归的思想,比如说把十个g的文件给他,先分成5个g,5个g,那我如果想要归并的话,首先得确保这两个五个g的文件数据是有序的。那该怎么确保呢?是不是相当于又要继续划分下去,那这样划分下去,不是要划分死了吗?而且我们真正在归并的时候,为了效率提高,我们一定要借助于内存,而不是全部在慢吞吞的磁盘里面。
- 所以总的思路就是这样:首先把大文件给他平均分割成N份,然后保证每一份的大小都可以加载到内存当中(我必须借助于内存,没办法,不然纯硬盘里面就慢到猴年马月了),然后因为我等会儿要依托这个每一份的划分出来的小文件为基准量不断向上归并,所以说前提是这些划分出来的小文件必须有序,由于他们现在倒是能够加载到内存里面,所以说先把他们读到内存里面用快速排序把他们先排成有序的
- 然后在内存里面给它全部把数据排成有序之后再写回小文件当中。那么这时我们就达到了文件中归并的先决条件。现在都是一个一个有序的小文件了。
- 首先就是对磁盘当中的海量数据不断的读,然后用一个变量去控制一下,比如说我现在假定每个小文件里面的数据个数是十个,那么在不断读取的过程当中,每读到十个的时候,然后此时此刻停顿一下,把这十个数据给他,在内存当中快速排序一下,并且给他去创建一个新的文件,并且把这十个在内存当中已经有序的数据给他读到那个文件里面去。当然里面有一些具体的细节的话,就去处理一下就可以,包括边界问题呀等等代码逻辑处理好就可以。
- 然后接下来就是文件之间的归并。这时候就肯定不能在内存当中了,因为内存里面已经放不下两个文件合起来这么一个数据量。因为归并排序的话,它的空间复杂度必须是O(N)。然后如果说两两一归并的话,有个很恶心的问题,就是取名字的问题。我们虽然采用非递归归并,但其实也可以不用去两两一归并,可以如下:

实际代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define ALL_NUMBER 10000
#define EVERY_NUMBER 1000
#define NAME_MAX 100
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
int GetMidNumi(int* arr, int left, int right)
{int mid = (left + right) / 2;if (arr[left] < arr[mid]){if (arr[left] > arr[right]){return left;}else{return arr[mid] < arr[right] ? mid : right;}}else{if (arr[right] > arr[left]){return left;}else{return arr[mid] > arr[right] ? mid : right;}}
}
void QuickSort(int* arr, int left, int right)
{if (left >= right){return;}int begin = left;int end = right;int midi = GetMidNumi(arr, left, right);Swap(arr + left, arr + midi);int keyi = left;while (left < right){while (left < right && arr[right] >= arr[keyi]){right--;}while (left < right && arr[left] <= arr[keyi]){left++;}Swap(arr + left, arr + right);}Swap(arr + left, arr + keyi);keyi = left;QuickSort(arr, begin, keyi - 1);QuickSort(arr, keyi + 1, end);
}
void CreateNumber()
{srand((unsigned int)time(NULL));FILE* pf = fopen("number.txt", "w");if (pf == NULL){perror("fopen failed");return;}for (int i = 0; i < ALL_NUMBER; i++){int num = rand();fprintf(pf, "%d\n", num);}fclose(pf);pf = NULL;
}
void MergeSortFile(char* file1, char* file2, char* file)
{FILE* pf1 = fopen(file1, "r");if (pf1 == NULL){perror("fopen failed");return;}FILE* pf2 = fopen(file2, "r");if (pf2 == NULL){perror("fopen failed");return;}FILE* pf = fopen(file, "w");if (pf == NULL){perror("fopen failed");return;}int num1 = 0;int num2 = 0;int ret1 = fscanf(pf1, "%d", &num1);int ret2 = fscanf(pf2, "%d", &num2);while (ret1 != EOF && ret2 != EOF){if (num1 < num2){fprintf(pf, "%d\n", num1);ret1 = fscanf(pf1, "%d", &num1);}else{fprintf(pf, "%d\n", num2);ret2 = fscanf(pf2, "%d", &num2);}}while (ret1 != EOF){fprintf(pf, "%d\n", num1);ret1 = fscanf(pf1, "%d", &num1);}while (ret2 != EOF){fprintf(pf, "%d\n", num2);ret2 = fscanf(pf2, "%d", &num2);}fclose(pf1);fclose(pf2);fclose(pf);
}
void Cover(char* file1, char* file2)
{FILE* pf1 = fopen(file1, "r");if (pf1 == NULL){perror("fopen failed");return;}FILE* pf2 = fopen(file2, "w");if (pf2 == NULL){perror("fopen failed");return;}int num = 0;int res = 0;while (fscanf(pf1, "%d", &num) != EOF){fprintf(pf2, "%d\n", num);}fclose(pf1);fclose(pf2);
}
int main()
{CreateNumber();FILE* pf = fopen("number.txt", "r");if (pf == NULL){perror("fopen failed");return;}int arr[EVERY_NUMBER] = { 0 };char file1[NAME_MAX] = { 0 };char file2[NAME_MAX] = { 0 };char file[NAME_MAX] = { 0 };int res = 0;int i = 0;int count = 0;while ((res = fscanf(pf, "%d", &arr[i++])) != EOF){if (i == EVERY_NUMBER){count++;if (count == 1){sprintf(file1, "%d", count);}sprintf(file2, "%d", count);QuickSort(arr, 0, EVERY_NUMBER - 1);i = 0;FILE* _pf = fopen(file2, "w");if (_pf == NULL){perror("fopen failed");return 1;}for (int j = 0; j < EVERY_NUMBER; j++){fprintf(_pf, "%d\n", arr[j]);}fclose(_pf);if (count > 1){sprintf(file, "%s%s", file1, file2);MergeSortFile(file1, file2, file);strcpy(file1, file);}}}fclose(pf);Cover(file, "number.txt");return 0;
}
相关文章:
(排序10)归并排序的外排序应用(文件排序)
TIPS 在一些文件操作函数当中,fputc与fgetc这两个函数都是针对字符的,如果说你需要往文件里面去放入整形啊等等,不是字符的类型,这时候就用fprintf,fscanf在参数里面数据类型控制一下就可以。但是话说回来,…...
浅谈根号分治与分块
文章目录 1. 根号分治哈希冲突 2. 线性分块引入教主的魔法[CQOI2011] 动态逆序对[国家集训队] 排队[HNOI2010] 弹飞绵羊蒲公英 1. 根号分治 哈希冲突 题目1 n n n 个数, m m m 次操作。操作 1 为修改某一个数的值,操作 2 为查询所有满足下标模 x x x …...
(OpenAI)ChatGPT注册登录常见问题错误代码及其解决方法
在使用 ChatGPT 的时候我们可能会碰到一些错误的代码,本文统一来介绍一下每一种错误以及解决方法。 错误代码1. 不能在当前国家使用 出现场景:一般在注册或登录的时候会出现。 原因:主要是ChatGPT检测到当前访问所在的地区不允许访问导致。 …...
MySQL主从复制、读写分离(MayCat2)实现数据同步
文章目录 1.MySQL主从复制原理。2.实现MySQL主从复制(一主两从)。3.基于MySQL一主两从配置,完成MySQL读写分离配置。(MyCat2) 1.MySQL主从复制原理。 MySQL主从复制是一个异步的复制过程,底层是基于Mysql数…...
Linux 云服务器好用吗?(解读Linux云服务器的特点优势)
如今,云计算越来越受欢迎,许多公司正在将业务转移到那里。企业向云过渡的主要原因是它提供的众多服务,包括安全和充足的存储、数据库、服务器和其他关键元素。 作为相对前|沿的技术之一,云建立在虚拟服务器上。Linux 服务器…...
研读Rust圣经解析——Rust learn-8(match,if-let简洁控制流,包管理)
研读Rust圣经解析——Rust learn-8(match,if-let简洁控制流,包管理) matchother和占位符_区别 easy matchenum matchno valuematch inner Option matchmore better way if-let整洁控制包管理模块(mod)拆分声明modpub公开use展开引用拆解模块结…...
G8期刊《全体育》期刊简介及投稿要求
G8期刊《全体育》期刊简介及投稿要求 《全体育》是由湖南体育产业集团有限公司主管、体坛传媒集团股份有限公司主办、中教体育 出版发行的体育综合性期刊。 主管:湖南体育产业集团有限公司 主办:体坛传媒集团股份有限公司 国内刊号:CN4…...
数据结构和算法学习记录——层序遍历(层次遍历)、二叉树遍历的应用(输出二叉树中的叶节点、求二叉树的高度、二元运算表达式树及其遍历、由两种遍历序列确定二叉树)
目录 层序遍历 思路图解 代码实现 二叉树遍历的应用 输出二叉树中的叶节点 代码实现 求二叉树的高度 思路图解 代码实现 二元运算表达式树及其遍历 由两种遍历序列确定二叉树 层序遍历 层序遍历可以通过一个队列来实现,其基本过程为: 先根…...
【Neo4j数据库】图数据库_Neo4j增加节点(关系)、查询、删除数据库等操作解析(Cypher语句)
【Neo4j数据库】图数据库_Neo4j增加节点(关系)、查询、删除操作解析(Cypher语句) 文章目录 【Neo4j数据库】图数据库_Neo4j增加节点(关系)、查询、删除操作解析(Cypher语句)1. 介绍2…...
Linux移动文件和文件夹(目录)命令
命令mv 英文move 翻译移动 mv命令可以移动文件或文件夹(目录),也可以重命令(覆盖)文件。 1. 移动文件/重命名 单纯地移动某一个文件直接使用: mv <源文件名称/地址> <新文件名称/地址>这个方法…...
Pandas的应用-5
Pandas是一个强大的数据处理库,它提供了高性能、易于使用的数据结构和数据分析工具。本文将介绍Pandas常用的数据结构和常用的数据分析技术,包括DataFrame的应用、窗口计算、相关性判定、Index的应用、范围索引、分类索引、多级索引以及日期时间索引。 …...
java继承类怎么写
继承类是通过把父类的方法和属性继承到一个类中,而子类的方法和属性是子类自己定义的。 Java中有一个很重要的概念叫做继承,这也是 Java语言的精髓所在。Java语言提供了一种机制,叫做派生类。在 Java中,如果没有实现了某个派生类方…...
面向对象程序设计
OOP 【面向对象程序设计】(OOP)与【面向过程程序设计】在思维方式上存在着很大的差别。【面向过程程序设计】中,算法是第一位的,数据结构是第二位的,这就明确地表述了程序员的工作方式。首先要确定如何操作数据&#…...
Linux 用户身份切换(su,sudo)
文章目录 Linux 用户身份切换su使用案例 sudo使用案例 visudo与/etc/sudoers单一用户可使用root所有命令,与sudoers文件语法利用wheel用户组以免密码的功能处理visudo有限制的命令操作通过别名创建visudosudo的时间间隔问题sudo搭配su的使用方式 Linux 用户身份切换…...
求倒置数问题
文章目录 求倒置数程序设计程序分析求倒置数 【问题描述】数组A【0,…,n-1】是一个n个不同整数数构成的数组。如果i<j,但是A[i]〉A[j],则这对元素(A[i],A[j])被称为一个倒置(inversion)。设计一个O(nlogn)算法来计算数组中的倒置数量 【输入形式】输入两行,第一行…...
sed(学习)
1、清除环境变量 profile~/.bash_profile sed -i s#export LD_LIBRARY_PATH.*##g $profile 2、设置环境变量(替换值) sed -i s#export LD_LIBRARY_PATH.*#export LD_LIBRARY_PATH/opt/testlinux/lib#g ~/.bash_profile 3、修改配置文件 sdk_dir/root/test log_dir/…...
B - GCD Subtraction
文章目录 AtCoder Regular Contest 159B - GCD Subtraction AtCoder Regular Contest 159 B - GCD Subtraction 问题:每次A,B都减去gcd(A,B),求其中一个减到0至少需要多少次主要思路: 首先第一步应该想到每次减去的数,先减去的数…...
解决Failed to load ApplicationContext问题的思路
中文翻译: 加载ApplicationContext失败 第一步:首先检查测试类的注解 以及 依赖 SpringBootTest <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scop…...
基于CAMX大气臭氧来源解析模拟与臭氧成因分析实践技术应用
查看原文>>>基于CAMX大气臭氧来源解析模拟与臭氧成因分析实践技术应用 目录 专题一、大气臭氧污染来源及成因分析技术讲解;CAMx模式初识及臭氧来源解析模拟本地案例配置说明 专题二、CAMx模式编译安装及空气质量模拟案例配置 专题三、CAMx扩展和探测工…...
异常的讲解 (1)
目录 异常入门的案例 异常介绍 基本概念 异常的小结 常见的运行时异常 1.NullPointerException空指针异常 2.ArithmeticException数学运算异常 3.ArraylndexOutOfBoundsException数组下标越界异常 4.ClassCastException类型转换异常 5.NumberFormatException数字格式不…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...
电脑桌面太单调,用Python写一个桌面小宠物应用。
下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡,可以响应鼠标点击,并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...
