使用的是VScode编辑器,VSCode在调试时程序文件不能以中文命名,因为中文会乱码。
一、inputNumb.c生成随机数程序
一行有10个。
/**
* @file InputNumb.c 生成随机数,并且拷贝
* @brief
* @version 0.1
* @date 2022-08-19
*
* @copyright Copyright (c) 2022
*
*/
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
void Input(int n);
int main()
{
int n;
printf("Input number:");
scanf("%ld", &n);
Input(n);
printf("Successful!\n");
}
void Input(int n)
{
int i;
FILE* fpinit = fopen("init.docx", "w");
if (fpinit == NULL) {
printf("生成随机init数文件打开失败!\n");
return;
}
srand((unsigned)time(NULL)); //或srand(time(0));
for (i = 1; i <= n; i++) {
fprintf(fpinit, "%ld", rand() * rand()); //两次输入确保输入的数的值超过long long,存入文件中
fprintf(fpinit, "%ld", rand() * rand());
fprintf(fpinit, "%s", " ");
if(i % 10 == 0) {
fprintf(fpinit, "%s", "\n");
}
}
fclose(fpinit);
}
二、largeNumbSort.c对随机数排序
1、对排序分为两次。
2、第一次,在为20个数据中排序放入文件中,完成后那就是部分有序。
3、第二次,归并排序,将数据归并到另一个文件中,最后再归并回去直到有序,如第一次从[1到20]和[21到40]归并,[41到60]和[61到80]归并···第二次从[1到40]和[41到80]归并,[81到120]和[121到160]归并···第n次直到结束。
#include <time.h>
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#define STRLEN 30 //字符串长度
#define STRNUM 20
void copy();
void SortData(FILE* fpdata, FILE* fpsort);
int FirstSort(FILE* fpdata, FILE* fpsort);
void ShellSort(char (*str)[STRLEN], int n); //str [长度]
void FileWrite(FILE* fpsort, char (*str)[STRLEN], int n);
void SecondSort(FILE* fpdata, int countsum);
void Classify(FILE* fpdata, int countsum, int n, int numb);
int MergeSort(FILE* fpsort, long nums[], int n, int numb);
int Compare(char* str1, char* str2);
int main(void)
{
long n;
FILE* fpdata, *fpsort;
printf("Running......\n");
copy();
SortData(fpdata, fpsort);
printf("Finish!\n");
return 0;
}
void copy()
{
int n = 0;
char str[STRLEN];
FILE* fp, *fpinit;
fp = fopen("data.docx", "w");
fpinit = fopen("init.docx", "r");
while(fscanf(fpinit, "%s", str) == 1) {
fprintf(fp, "%s", str);
fprintf(fp, "%s", " ");
n++;
if(n % 10 == 0) {
fprintf(fp, "%s", "\n");
}
}
if(n == 0) {
printf("No data!\n");
return;
}
fclose(fp);
fclose(fpinit);
}
/**
* @brief (数据读入 排序 写入text) (从text读出两个对比 归并排序并写入文件)
*
* @param fpdata
* @param fpsort
*/
void SortData(FILE* fpdata, FILE* fpsort)
{
int countsum; //统计总个数
/*第一次*/
countsum = FirstSort(fpdata, fpsort);
/*第二次排序*/
SecondSort(fpdata, countsum);
}
/**
* @brief 确定要排序的数,并且每20个做希尔排序
*
* @param fpdata 读文件
* @param fpsort 写文件
* @return int 数据总个数
*/
int FirstSort(FILE* fpdata, FILE* fpsort)
{
int countsum = 0;
char str[STRNUM][STRLEN]; //20
fpsort = fopen("text.docx", "w");
fpdata = fopen("data.docx", "r");
if(fpsort == NULL || fpdata == NULL){
printf("FirstSort第一次排序文件打开失败!");
return 0;
}
while(fscanf(fpdata, "%s", str[countsum % STRNUM]) == 1){
countsum++;
if(countsum % STRNUM == 0){
ShellSort(str, STRNUM); //排序写入;
//这里增加修改成多线程排序
FileWrite(fpsort, str, STRNUM);
}
}
fclose(fpdata);
fclose(fpsort);
return countsum;
}
/**
* @brief 希尔排序
*
* @param n 排序个数
* 传入的是字符指针
*/
void ShellSort(char (*str)[STRLEN], int n) // n: 20
{
int i, j;
char s[STRLEN];
int h = 13; //for (h = 0; h < n / 3; h = h * 3 + 1);
for (h = h; h > 0; h = h / 3) {
for (i = h; i < n; i++) {
j = i;
strncpy(s, str[i], STRLEN);
while (j >= h && Compare(s, str[j - h])) { //Compare(char* str1, char* str2); 0: str1大, 1: str2大
strncpy(str[j], str[j - h], STRLEN);
j = j - h;
}
strncpy(str[j], s, STRLEN);
}
}
}
/**
* @brief 把排好序的数组写入文件
*
* @param fpsort 写入文件指针
* @param n 数组个数
*/
void FileWrite(FILE* fpsort, char (*str)[STRLEN], int n)
{
int i;
for(i = 1; i <= n; i++){
fprintf(fpsort, "%s", str[i - 1]);
fprintf(fpsort, "%s", " ");
if (i % 10 == 0) {
fprintf(fpsort, "%s", "\n");
}
}
}
/**
* @brief 确定有序序列的个数,传入分类函数
*
* @param fpdata 读数据,判断归并排序的起始和终止位置
* @param countsum 数据总个数
*/
void SecondSort(FILE* fpdata, int countsum)
{
int numb = 0; //判断哪个文件读那个写
int n = 0; // 归并有序数列个数 n: 20 40 80 160 320 640 1280 2560 5120/5000
for (n = 20; n <= countsum; n = n * 2) {
if (numb % 2 == 0) {
fpdata = fopen("text.docx", "r");
}
else {
fpdata = fopen("data.docx", "r");
}
if (fpdata == NULL) {
printf("fpdata:判断归并排序的起始和终止位置的文件读取失败!\n");
break;
}
Classify(fpdata, countsum, n, numb);
fclose(fpdata);
numb++;
}
}
/**
* @brief 归并排序分步进行
*
* @param fpdata 读数据,判断归并排序的起始和终止位置
* @param countsum 数据总个数
* @param n 归并有序数列个数 n: 20 40 80 160 320 640 1280 2560 5120/5000...
* @param numb 判断哪个文件读,哪个文件写
* 注意点
* 1、数组中有三个,但是是求余2,nums[0] = nums[2]
* 2、奇数组别考虑:最后一组不满足80或XXX个时
*/
void Classify(FILE* fpdata, int countsum, int n, int numb)
{
int m = 0; //计数个数,判断换行,写文件中
int count = 0; //记录数据个数,判断终止,读文件中
char s[STRLEN]; //作为文件读出储存字符串,没有太大意义
int num = 0; //确定存入nums的位置,首个nums[0] = 0;
FILE* fpsort, *fp; //fpsort 写入文件, fp 没有两两匹配数据的读入,读数据
long nums[3] = { 0 }; //nums[0]: 第一组位置; nums[1]: 第二组数据,第一组结尾; nums[2]: 第二组结尾。
if(numb % 2 == 0) {
fpsort = fopen("data.docx", "w");
}
else {
fpsort = fopen("text.docx", "w");
}
if (fpsort == NULL) {
printf("fpsort:写入数据的文件打开失败!\n");
return;
}
while (fscanf(fpdata, "%s", s) == 1) { //确定nums[]数组,并传入排序函数
count++;
if (count % n == 0 || count == countsum) {
if (num % 2 == 0) {
nums[1] = ftell(fpdata);
}
else {
nums[2] = ftell(fpdata);
}
num++;
if(num % 2 == 0) { //确定读入两组,进入排序
m = MergeSort(fpsort, nums, m, numb);
nums[0] = nums[2];
}
}
}
if (m < countsum) { //考虑读文件最后没有两两匹配数据的读入
if (numb % 2 == 0) {
fp = fopen("text.docx", "r");
}
else {
fp = fopen("data.docx", "r");
}
if (fp == NULL) {
printf("最后没匹配数据文件读取失败!\n");
}
fseek(fp, nums[0], SEEK_SET);
while (fscanf(fp, "%s", s) == 1) {
fprintf(fpsort, "%s", s);
fprintf(fpsort, "%s", " ");
m++;
if (m % 10 == 0) {
fprintf(fpsort, "%s", "\n");
}
}
fclose(fp);
}
fclose(fpsort);
}
/**
* @brief 归并排序
*
* @param fpsort 写入的文件指针
* @param nums 判断文件指针起止位置
* @param n 写入文件个数 20 40 80 ...
* @param numb 判断哪个文件读
* @return int 写入文件数据个数
*/
int MergeSort(FILE* fpsort, long nums[], int n, int numb)
{
char str1[STRLEN], str2[STRLEN];
FILE* fpdata1, *fpdata2;
if (numb % 2 == 0) {
fpdata1 = fopen("text.docx", "r");
fpdata2 = fopen("text.docx", "r");
}
else {
fpdata1 = fopen("data.docx", "r");
fpdata2 = fopen("data.docx", "r");
}
if (fpdata1 == NULL || fpdata2 == NULL) {
printf("fpdata1或fpdata2:归并排序时的文件读取失败!\n");
return n;
}
fseek(fpdata1, nums[0], SEEK_SET);
fseek(fpdata2, nums[1], SEEK_SET);
fscanf(fpdata1, "%s", str1);
fscanf(fpdata2, "%s", str2);
n++;
while (1) {
if (Compare(str1, str2) == 1) {
fprintf(fpsort, "%s", str1);
fprintf(fpsort, "%s", " ");
fscanf(fpdata1, "%s", str1);
}
else {
fprintf(fpsort, "%s", str2);
fprintf(fpsort, "%s", " ");
fscanf(fpdata2, "%s", str2);
}
if (ftell(fpdata1) > nums[1]) {
if (n % 10 == 0) {
fprintf(fpsort, "%s", "\n");
}
while (ftell(fpdata2) <= nums[2]) {
fprintf(fpsort, "%s", str2);
fprintf(fpsort, "%s", " ");
fscanf(fpdata2, "%s", str2);
n++;
if (n % 10 == 0) {
fprintf(fpsort, "%s", "\n");
}
}
break;
}
if (ftell(fpdata2) > nums[2]) {
if (n % 10 == 0) {
fprintf(fpsort, "%s", "\n");
}
while (ftell(fpdata1) <= nums[1]) {
fprintf(fpsort, "%s", str1);
fprintf(fpsort, "%s", " ");
fscanf(fpdata1, "%s", str1);
n++;
if (n % 10 == 0) {
fprintf(fpsort, "%s", "\n");
}
}
break;
}
if (n % 10 == 0) {
fprintf(fpsort, "%s", "\n");
}
n++;
}
fclose(fpdata1);
fclose(fpdata2);
return n;
}
/**
* @brief 比较字符串大小
*
* @return int 0: str1大, 1: str2大
*/
int Compare(char* str1, char* str2) //0: str1大, 1: str2大
{
int i;
int len1 = strlen(str1);
int len2 = strlen(str2);
if (len1 > len2) {
return 0;
}
else if (len1 < len2) {
return 1;
}
else {
for (i = 0; i <= len2; i++) {
if (str1[i] > str2[i]) {
return 0;
}
else if (str1[i] < str2[i]) {
return 1;
}
}
}
return 0;
}
三、compareNumber.c对排好序的文件进行核对
升序排序成功输出bye,若有错则输出有错的位置i。
#include<stdio.h>
#include<string.h>
int Compare(char* str1, char* str2);
int main()
{
FILE* fp;
int i = 0;
char str[2][30];
fp = fopen("data.docx", "r");
while (fscanf(fp, "%s", str[i % 2]) == 1) {
i++;
if (i % 2 == 0) {
if(Compare(str[0], str[1]) == 0) {
printf(" i: %d error\n", i);
break;
}
}
}
printf("bye\n");
}
int Compare(char* str1, char* str2) //0: str1大, 1: str2大
{
int i;
int len1 = strlen(str1);
int len2 = strlen(str2);
if (len1 > len2) {
return 0;
}
else if (len1 < len2) {
return 1;
}
else {
for (i = 0; i <= len2; i++) {
if (str1[i] > str2[i]) {
return 0;
}
else if (str1[i] < str2[i]) {
return 1;
}
}
}
return 0;
}
四、运行
1.inputNumb.c
输入:input number: 100万
运行结束:Successful!
下图位生成随机数图片。
2.largeNumbSort.c
运行会产生3个文件,init.docx时原始生成的随机数源文件,data.docx是排序好的文件,text.docx是归并排序中转文件。
正在运行:Running······
运行成功:Finishing!
下图位排好序的图片。
3.compareNumber.c
验证升序排序成功输出bye,若有错则输出有错的位置i, 是第i个错误。
下图为验证升序排序是否有误。
运行终端多了一个input是当时运行顺序错误了,但程序没有错。
3.对100万的数据排序大概要10几秒,但还是太慢,还可以添加多线程进行排序。
4.本次数据最小为3068350,最大为10485354041056310776(20位)。
你所做的努力都会在你人生中的某一天给与你会报。