大数外部排序

题意:将百万级数据排序,已知内存最大处理4K数据

 

4K内存容量是4000字节,也就是说能处理1000个数假如说现在有N数据进行排序,N为百万级,而内存一次只能处理1000个数据,我们做法是分部做,即先把N分成N/1000份数据,这样每份数据就都能用内部排序方法实现(本题使用2路),每份数据存在一个文件里然后再把这些文件合并。

 

具体实现过称为:假设原文件存储在test.txt中分别从总数据test中fscanf读取1000个数据,每个文件依次命名1,2,3……理论是N/1000个,即filenum个文件(最后一个文件数据个数不一定为1000),每个文件中数据使用二路归并排序SortFile排好,接下来就是对filenum组数据进行排序,即调用MergeFile函数归并,一般来说这一步使用多路归并、败者树方法,当然也可以二路归并本题采用”二路归并“:使用非递归,两两合并(个数为奇数最后一个不用归),使用file_tag标记进行到第几组了,file_tag==filenum那么第一次循环归并就结束了,get_filenum记录得到的归并文件数,之前的文件使用remove删去,每次循环文件总数总要用新得到的归并文件总数代替filenum=get_filenum,直到文件数filenum为1那么就完成了

纯C代码:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#define MAXNUM 2000

///全局变量
int filenum;///当前文件数
int file_tag;///标记归并到哪个文件了
int get_filenum;///记录归并得到的文件数

///函数声明
void CreatFile();//用于获取100万个随机数
void SortFile();//将100万个随机数拆分为filenum个文件,每拆分好一个便内部排序,调用了函数CreatdataFile、merge_sort
void CreatdataFile(int data[], int count);//将data数组中排好的数据写入到文件中
void merge_sort(int num[], int start, int end);//二路归并排序函数
void merge(int num[], int start, int mid, int end);//两个有序数组的合并,与上一个函数构成完整二路归并排序函数
void MergeFile();//对于已经排好序的filenum个文件采取两两合并


int main()
{
    CreatFile(); //生成10000个随机数存储在test.txt文件中
    SortFile(); //初次切割并排序为有序文件
    MergeFile(); //对文件进行归并排序
    return 0;
}

void CreatFile()//用于获取100万个随机数
{
    FILE *f;
    f = fopen("test.txt", "w+");
    //srand((unsigned)time(NULL));
    for (int i = 0; i < 10000; ++i)
    {
        int data = rand() % 100; //产生0-100的随机数
        fprintf(f, "%d\n", data);

    }
    fclose(f);
}

void SortFile()//将100万个随机数拆分为filenum个文件,每拆分好一个便内部排序,调用了函数CreatdataFile、merge_sort
{
    FILE *f;
    f = fopen("test.txt", "r");
    int *data;
    data = (int *)malloc(MAXNUM * sizeof(int));
    char datachar;
    int count = 0;
    while (fscanf(f, "%d", &data[count])!=EOF)
    {
        count++;
        if (count == MAXNUM)
        {
            filenum++;
            merge_sort(data, 0, count - 1);
            CreatdataFile(data, count);
            count = 0;
        }
    }
    if (count != 0)
    {
        filenum++;
        CreatdataFile(data, count);
        count = 0;
    }
    fclose(f);
    free(data);
}

///将data中排好的数据写入到文件中1,2,3,4
void CreatdataFile(int data[], int count)
{
    FILE *f;
    char filename[10] = { "" };
    filename[0] = filenum + '0';
    strcat(filename, ".txt");
    f = fopen(filename, "w+");
    for (int i = 0; i < count; ++i)
    {
        fprintf(f, "%d\n", data[i]);
    }
    fclose(f);
}

///二路归并排序
void merge_sort(int num[], int start, int end)
{
    int mid;
    if (start < end)
    {
        mid = (start + end) / 2;

        merge_sort(num, start, mid);
        merge_sort(num, mid + 1, end);
        merge(num, start, mid, end);
    }
}

void merge(int num[], int start, int mid, int end)
{
    int n1 = mid - start + 1;
    int n2 = end - mid;
    int *left, *right;
    left = (int*)malloc(n1 * sizeof(int));
    right = (int*)malloc(n2 * sizeof(int));
    int i, j, k;

    for (i = 0; i < n1; i++)
        left[i] = num[start + i];
    for (j = 0; j < n2; j++)
        right[j] = num[mid + 1 + j];

    i = j = 0;
    k = start;
    while (i < n1 && j < n2)
        if (left[i] < right[j])
            num[k++] = left[i++];
        else
            num[k++] = right[j++];

    while (i < n1)
        num[k++] = left[i++];

    while (j < n2)
        num[k++] = right[j++];

    free(left);
    free(right);
}

///file_tag标记进行到第几组
///get_filenum归并得到的文件数目
void MergeFile()
{
    file_tag = 0;
    while (filenum != 1)
    {
        while (file_tag < filenum)
        {
            if ((filenum - file_tag) == 1)
            {
                FILE *f1, *f;

                char filename1[10] = { "" };
                file_tag++;
                filename1[0] = file_tag + '0';
                strcat(filename1, ".txt");
                f1 = fopen(filename1, "r");

                ///
                get_filenum++;
                char filename[10] = { "" };
                filename[0] = get_filenum + '0';
                strcat(filename, "data.txt");
                f = fopen(filename, "w+");

                int num1;
                while (fscanf(f1, "%d", &num1) != EOF)
                {
                    fprintf(f, "%d\n", num1);
                }
                fclose(f1);
                fclose(f);
            }
            else
            {
                FILE *f1, *f2, *f;
                char filename1[10] = { "" };
                file_tag++;
                filename1[0] = file_tag + '0';
                strcat(filename1, ".txt");
                f1 = fopen(filename1, "r");

                char filename2[10] = { "" };
                file_tag++;
                filename2[0] = file_tag + '0';
                strcat(filename2, ".txt");
                f2 = fopen(filename2, "r");

                get_filenum++;
                char filename[10] = { "" };
                filename[0] = get_filenum + '0';
                strcat(filename, "data.txt");
                f = fopen(filename, "w+");

                int data;
                int count = 0;
                int num1, num2;
                fscanf(f1, "%d", &num1);
                fscanf(f2, "%d", &num2);
                while (1)
                {
                    if (num1 < num2)
                    {
                        fprintf(f, "%d\n", num1);
                        if (fscanf(f1, "%d", &num1) == EOF)
                        {
                            fprintf(f, "%d\n", num2);
                            while (fscanf(f2, "%d", &num2) != EOF)
                            {
                                fprintf(f, "%d\n", num2);
                            }
                            break;
                        }
                    }
                    else
                    {
                        fprintf(f, "%d\n", num2);
                        if (fscanf(f2, "%d", &num2) == EOF)
                        {
                            fprintf(f, "%d\n", num1);
                            while (fscanf(f1, "%d", &num1) != EOF)
                            {
                                fprintf(f, "%d\n", num1);
                            }
                            break;
                        }
                    }
                }
                fclose(f1);
                fclose(f2);
                fclose(f);
            }

            char filename1[10] = { "" };
            char filename2[10] = { "" };
            filename1[0] = get_filenum + '0';
            filename2[0] = get_filenum + '0';
            strcat(filename1, "data.txt");
            strcat(filename2, ".txt");

            char filename3[10] = { "" };
            char filename4[10] = { "" };
            //假如说归并得到第3个文件,那么产生它的对应的文件为5,6两个
            filename3[0] = get_filenum * 2 - 1 + '0';
            filename4[0] = get_filenum * 2 + '0';
            strcat(filename3, ".txt");
            strcat(filename4, ".txt");

            int r1 = remove(filename3);
            int r2 = remove(filename4);
            printf("r1=%d r2=%d\n", r1, r2);
            // int rename ( const char * oldname, const char * newname )
            rename(filename1, filename2);

            //printf("filenum=%d file_tag=%d get_filenum=%d\n", filenum, file_tag, get_filenum);
            if (file_tag == filenum&&filenum != 1)
            {
                filenum = get_filenum;
                file_tag = 0;
                get_filenum = 0;
            }
        }
    }
    char filename1[20] = { "" };
    char filename2[20] = { "" };
    filename1[0] = 1 + '0';
    strcat(filename1, ".txt");
    strcat(filename2, "test_sort.txt");
    rename(filename1, filename2);
    printf("排序完成,有序序列保存在:test_sort.txt文件中\n");
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值