对大量的随机数排序——用文件排序

使用的是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位)。
排序好文件的首部你所做的努力都会在你人生中的某一天给与你会报。
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值