利用归并排序对大容量文件排序

简介:

@[TOC]

前言:

  • 本文介绍,归并排序解决大容量排序问题,声明:是模拟这个过程。
  • 本文需要文件一定==文件操作知识==尤其是 sscanf和sprintf的使用:博客
  • 博主收集的资料New Young,连载中。
  • 博主收录的问题:New Young
  • 转载请标明出处:New Young

问题

如果一个文件有4G大小待排序的数据,而内存大小为1G,请问怎么对文件进行排序。

思路

image-20220302213901920

分割排序文件

效果

image-20220302221923577

代码

void SortSmallFile(const char* filename, int x, int y)
{

    assert(filename);
    FILE* PF = fopen(filename, "r+");
    assert(PF != NULL);
    int n = x/ y;
    int* arr = (int*)calloc(n, sizeof(int));
    assert(arr);


    char smallfile[100] = { 0 };
    int filei = 0;
    int i = 0;
    int out = 0;

    while (!feof(PF))
    {
        if (i<n-1)
        {
            fscanf(PF, "%d\n", &out);

            arr[i++] = out;
    
        }
        else
        {
            if (!feof(PF))
            {
                fscanf(PF, "%d\n", &out);
                arr[i++] = out;
            }
            
            //排序数组
            QuickSort(arr, 0, i - 1);
            sprintf(smallfile, "date\\date_file%d", filei++);
            //开始拷贝到文件中
            FILE* pf = fopen(smallfile, "w");
            assert(pf != NULL);
            int cnt = 0;
            while (cnt < i)
            {
                fprintf(pf, "%d\n", arr[cnt++]);
            }

            i = 0;//重置i
            fclose(pf);
            pf = NULL;
        }
    }
    free(arr);
    arr = NULL;
    fclose(PF);
    PF = NULL;
}

归并文件

效果

image-20220302221948257

代码

void _MergeSortFile(const char* file1, const char* file2, const char* tmpfile)
{
    assert(file1);
    assert(file2);
    assert(tmpfile);
    FILE* pf1 = fopen(file1, "r");
    assert(pf1 != NULL);
    FILE* pf2 = fopen(file2, "r");
    assert(pf2 != NULL);
    FILE* tmppf = fopen(tmpfile,"w");
    assert(tmppf != NULL);
    
    int out1= 0;
    int out2 = 0;
    fscanf(pf1, "%d\n", &out1);
    fscanf(pf2, "%d\n", &out2);
    
    while (!feof(pf1)&&!feof(pf2))
    {
        if (out1 <= out2)
        {
            fprintf(tmppf, "%d\n", out1);
            fscanf(pf1, "%d\n", &out1);
        }
        else
        {
            fprintf(tmppf, "%d\n", out2);
            fscanf(pf2, "%d\n", &out2);
        }
    }

    while (!feof(pf1))
    {
        fprintf(tmppf, "%d\n", out1);
        fscanf(pf1, "%d\n", &out1);

    }
    while (!feof(pf2))
    {
        fprintf(tmppf, "%d\n", out2);
        fscanf(pf2, "%d\n", &out2);

    }
    fclose(pf1);
    pf1 = NULL;
    fclose(pf2);
    pf2 = NULL;
    fclose(tmppf);
    tmppf = NULL;
}
    
    char file1[100] = "date\\date_file0";
    char file2[100] = "date\\date_file1";
    char tmpfile[100] = "date2.0\\date_file01";
    int i = 0;
    _MergeSortFile(file1, file2, tmpfile);
    //这一步要控制好循环。
    for (i = 2; i < 10 ;++i)
    {
        sprintf(file1, "%s", tmpfile);
        sprintf(file2, "date\\date_file%d", i);
        sprintf(tmpfile, "%s%d", tmpfile, i);
        _MergeSortFile(file1, file2, tmpfile);

    }

赋值文件

效果

image-20220302222130343

代码

//数据再次存放到文件中中。
      
    FILE* PF = fopen(FileName, "w");
    assert(PF);

    char fin[100] = { 0 };
    sprintf(fin, "%s", tmpfile);
    FILE* pf = fopen(fin, "r");
    assert(pf);
    int cnt = 0;
    int out = 0;
    while (!feof(pf)&&cnt<M)
    {
        fscanf(pf, "%d\n", &out);
        fprintf(PF, "%d\n", out);
        cnt++;
    }
    fclose(PF);
    PF = NULL;
    fclose(pf);
    pf = NULL;

Sort.cpp

#include"sort.h"
void Swap(int* a, int* b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;

}
void InsertSort(int* a, int n)// 插入排序
{
    assert(a);
    for (int i = 0; i < n - 1; ++i)
    {
        int x = a[i + 1];
        int end = i;
        while (end >= 0)
        {
            if (a[end] > x)
            {
                a[end + 1] = a[end];

            }
            else
            {

                break;
            }
            end--;
        }
        a[end + 1] = x;
    }
}
int  GetMidIndex(int* a, int left, int right)
{
    assert(a);
    int mid = (left + right) / 2;
    if (a[left] >= a[mid])
    {
        if (a[mid] >= a[right])
        {
            return mid;
        }
        else//a[mid]<a[right].mid最小
        {
            if (a[right] > a[left])
            {
                return left;
            }
            else
            {
                return right;
            }
        }
    }
    else//a[left]<a[mid]
    {
        if (a[mid] < a[right])
        {
            return mid;
        }
        else//a[mid]>=a[right],mid是最大的
        {

            if (a[right] > a[left])
            {
                return right;
            }
            else
            {
                return  left;
            }
        }

    }

}

int PartSort1(int* a, int left, int right)// 快速排序hoare版本
{
    assert(a);
    //三数取中,是为了解决有序,栈溢出的问题。
    //通过取中,打乱有序。
    int key = GetMidIndex(a, left, right);
    Swap(&a[key], &a[left]);
    int keyi = left;
    while (left < right)
    {
        while (right > left && a[right] >= a[keyi])//从右开始,找第一个小于a[key]
        {
            --right;
        }
        while (left < right && a[left] <= a[keyi])//从左开始,找第一个大于[key]
        {
            ++left;
        }
        Swap(&a[left], &a[right]);
    }
    Swap(&a[keyi], &a[right]);
    return left;
}

void QuickSort(int* a, int left, int right)
{
    assert(a);
    if (left >= right)
    {
        return;
    }

    if (right - left < 10)//小区间优化,这可以减少递归的深度。
    {
        InsertSort(a + left, right - left + 1);
    }
    else
    {
        int key = PartSort1(a, left, right);
        
        QuickSort(a, left, key - 1);
        QuickSort(a, key + 1, right);
    }

}

main.cppp

#include"sort.h"
#define M 100
#define N 10



void SortSmallFile(const char* filename, int x, int y)
{

    assert(filename);
    FILE* PF = fopen(filename, "r+");
    assert(PF != NULL);
    int n = x/ y;
    int* arr = (int*)calloc(n, sizeof(int));
    assert(arr);


    char smallfile[100] = { 0 };
    int filei = 0;
    int i = 0;
    int out = 0;

    while (!feof(PF))
    {
        if (i<n-1)
        {
            fscanf(PF, "%d\n", &out);

            arr[i++] = out;
    
        }
        else
        {
            if (!feof(PF))
            {
                fscanf(PF, "%d\n", &out);
                arr[i++] = out;
            }
            
            //排序数组
            QuickSort(arr, 0, i - 1);
            sprintf(smallfile, "date\\date_file%d", filei++);
            //开始拷贝到文件中
            FILE* pf = fopen(smallfile, "w");
            assert(pf != NULL);
            int cnt = 0;
            while (cnt < i)
            {
                fprintf(pf, "%d\n", arr[cnt++]);
            }

            i = 0;//重置i
            fclose(pf);
            pf = NULL;
        }
    }
    free(arr);
    arr = NULL;
    fclose(PF);
    PF = NULL;
}

void _MergeSortFile(const char* file1, const char* file2, const char* tmpfile)
{
    assert(file1);
    assert(file2);
    assert(tmpfile);
    FILE* pf1 = fopen(file1, "r");
    assert(pf1 != NULL);
    FILE* pf2 = fopen(file2, "r");
    assert(pf2 != NULL);
    FILE* tmppf = fopen(tmpfile,"w");
    assert(tmppf != NULL);
    
    int out1= 0;
    int out2 = 0;
    fscanf(pf1, "%d\n", &out1);
    fscanf(pf2, "%d\n", &out2);
    
    while (!feof(pf1)&&!feof(pf2))
    {
        if (out1 <= out2)
        {
            fprintf(tmppf, "%d\n", out1);
            fscanf(pf1, "%d\n", &out1);
        }
        else
        {
            fprintf(tmppf, "%d\n", out2);
            fscanf(pf2, "%d\n", &out2);
        }
    }

    while (!feof(pf1))
    {
        fprintf(tmppf, "%d\n", out1);
        fscanf(pf1, "%d\n", &out1);

    }
    while (!feof(pf2))
    {
        fprintf(tmppf, "%d\n", out2);
        fscanf(pf2, "%d\n", &out2);

    }
    fclose(pf1);
    pf1 = NULL;
    fclose(pf2);
    pf2 = NULL;
    fclose(tmppf);
    tmppf = NULL;
}

int main()
{
    char FileName[100] = "Date.txt";
    //文件分成N份,文件大小为M.并排序这些小文件---先存到数组,对数组排完序后放到文件中就行了。
    SortSmallFile(FileName, M, N);
    
    char file1[100] = "date\\date_file0";
    char file2[100] = "date\\date_file1";
    char tmpfile[100] = "date2.0\\date_file01";
    int i = 0;
    _MergeSortFile(file1, file2, tmpfile);
    //这一步要控制好循环。
    for (i = 2; i < 10 ;++i)
    {
        sprintf(file1, "%s", tmpfile);
        sprintf(file2, "date\\date_file%d", i);
        sprintf(tmpfile, "%s%d", tmpfile, i);
        _MergeSortFile(file1, file2, tmpfile);

    }

    //数据再次存放到文件中中。
      
    FILE* PF = fopen(FileName, "w");
    assert(PF);

    char fin[100] = { 0 };
    sprintf(fin, "%s", tmpfile);
    FILE* pf = fopen(fin, "r");
    assert(pf);
    int cnt = 0;
    int out = 0;
    while (!feof(pf)&&cnt<M)
    {
        fscanf(pf, "%d\n", &out);
        fprintf(PF, "%d\n", out);
        cnt++;
    }
    fclose(PF);
    PF = NULL;
    fclose(pf);
    pf = NULL;





return 0;

}
相关文章
|
9月前
|
存储 算法 搜索推荐
排序篇(四)----归并排序
排序篇(四)----归并排序
43 0
|
10月前
|
算法
|
2月前
|
机器学习/深度学习 算法 搜索推荐
DS:八大排序之归并排序、计数排序
DS:八大排序之归并排序、计数排序
|
2月前
|
存储 算法 搜索推荐
计数排序-解决海量数据排序
计数排序-解决海量数据排序
37 0
|
2月前
|
算法 搜索推荐
排序——归并排序
排序——归并排序
26 0
|
11月前
|
搜索推荐 算法
【八大排序之交换与归并排序】(二)
【八大排序之交换与归并排序】(二)
37 0
|
11月前
【八大排序之交换与归并排序】(一)
【八大排序之交换与归并排序】(一)
38 0
|
11月前
|
存储 算法 搜索推荐
【排序】排序这样写才对Ⅰ --插入排序与选择排序
常见的排序算法有这些.将会分成几个章节讲完,感兴趣的uu们可以关注下我的排序专栏,方便和后期观看.
42 0
|
12月前
|
存储 搜索推荐 算法
“插入排序:小数据量排序的王者“
“插入排序:小数据量排序的王者“
87 0
|
11月前
|
存储 算法 PHP
PHPHashtable 如何优化数组查找和排序
PHP 是一种高度流行的编程语言,被广泛用于web开发。它有很多的优点,例如易于学习、跨平台、简单易用的语法等等。而在 PHP 中,数组是一种非常常用的数据结构,它可以存储一组有序的数据,方便我们进行各种操作。
46 0

热门文章

最新文章

  • 1
    流量控制系统,用正则表达式提取汉字
    27
  • 2
    Redis09-----List类型,有序,元素可以重复,插入和删除快,查询速度一般,一般保存一些有顺序的数据,如朋友圈点赞列表,评论列表等,LPUSH user 1 2 3可以一个一个推
    26
  • 3
    Redis08命令-Hash类型,也叫散列,其中value是一个无序字典,类似于java的HashMap结构,Hash结构可以将对象中的每个字段独立存储,可以针对每字段做CRUD
    27
  • 4
    Redis07命令-String类型字符串,不管是哪种格式,底层都是字节数组形式存储的,最大空间不超过512m,SET添加,MSET批量添加,INCRBY age 2可以,MSET,INCRSETEX
    28
  • 5
    S外部函数可以访问函数内部的变量的闭包-闭包最简单的用不了,闭包是内层函数+外层函数的变量,简称为函数套函数,外部函数可以访问函数内部的变量,存在函数套函数
    24
  • 6
    Redis06-Redis常用的命令,模糊的搜索查询往往会对服务器产生很大的压力,MSET k1 v1 k2 v2 k3 v3 添加,DEL是删除的意思,EXISTS age 可以用来查询是否有存在1
    31
  • 7
    Redis05数据结构介绍,数据结构介绍,官方网站中看到
    22
  • 8
    JS字符串数据类型转换,字符串如何转成变量,+号只要有一个是字符串,就会把另外一个转成字符串,- * / 都会把数据转成数字类型,数字型控制台是蓝色,字符型控制台是黑色,
    20
  • 9
    JS数组操作---删除,arr.pop()方法从数组中删除最后一个元素,并返回该元素的值,arr.shift() 删除第一个值,arr.splice()方法,删除指定元素,arr.splice,从第一
    21
  • 10
    定义好变量,${age}模版字符串,对象可以放null,检验数据类型console.log(typeof str)
    19