[算法]外部排序

当排序内容太大,不足以全部放入内存进行内部排序,则可把排序内容按可用内存大小分割成多个文件,分别读取文件进行内排,排序结果继续写入文件。最后对所有文件进行归并排序合并成有序大文件。

外部排序步骤:1、分割数据 2、分别内排 3、归并小文件

// acm.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#pragma warning(disable: 4786)
#include <iostream>
#include <string>
#include <stdio.h>
#include <fstream>//加入这个头文件才可以操作文件
#include <vector>
#include <algorithm>
#include "Afx.h"
using namespace std;
//分割文件,每个文件n个数据
int divi_file(char* file_name,int n){
    ifstream in_file;
    in_file.open(file_name);
    if(!in_file)
        return 0;
    char buf[100];
    int count=0,n_file=0;
    ofstream out_file;
    while(!in_file.eof()){
        in_file.getline(buf,100);
        if(count==0){
            char f_name[20];
            sprintf(f_name,"%d.txt",n_file);
            out_file.open(f_name);
            n_file++;
        }
        out_file<<buf<<endl;
        count++;
        if(count>=n){
            count=0;
            out_file.close();
        }
    }
    out_file.close();
    in_file.close();
    return n_file;
}

//子文件内排序
void in_sort(int n_file){
    ofstream out_file;
    for(int i=0;i<n_file;++i){
        char f_name[20];
        sprintf(f_name,"%d.txt",i);
        ifstream in_file;
        in_file.open(f_name);
        vector<int> v_sort;
        char buf[100];
        while(!in_file.eof()){
            in_file.getline(buf,100);
            v_sort.push_back(atoi(buf));
        }
        sort(v_sort.begin(),v_sort.end());
        in_file.close();
        out_file.open(f_name);
        int len=v_sort.size();
        for(int j=1;j<len;++j){
            out_file<<v_sort[j];
            if(j!=len-1)
                out_file<<endl;
        }
        v_sort.clear();
        out_file.close();
    }
}

//归并两个文件
void merge_two(char* ifile1,char* ifile2,char* ofile){
    ifstream f1,f2;
    f1.open(ifile1);
    f2.open(ifile2);
    ofstream result;
    result.open(ofile);
    int c1,c2,done1=1,done2=1;
    while(!f1.eof() || !f2.eof() || done1==0 || done2==0){
        char buf[100];
        if(!f1.eof() && done1==1){
            f1.getline(buf,100);
            if(*buf!='\0'){
                c1=atoi(buf);
                done1=0;
            }
        }
        if(!f2.eof() && done2==1){
            f2.getline(buf,100);
            if(*buf!='\0'){
                c2=atoi(buf);
                done2=0;
            }
        }
        if(done1==0 && done2==0){
            if(c1<c2){
                result<<c1<<endl;
                done1=1;
            }else{
                result<<c2<<endl;
                done2=1;
            }
        }else{
            if(done1==0){
                result<<c1<<endl;
                done1=1;
            }
            if(done2==0){
                result<<c2<<endl;
                done2=1;
            }
        }
    }
    f1.close();
    f2.close();
    result.close();
}

//归并所有子文件
void merge_all(int n_file){
    if(n_file==1)
        return;
    int n=n_file/2;
    for(int i=0;i<n;++i){
        char f_name1[20],f_name2[20];
        sprintf(f_name1,"%d.txt",i);
        sprintf(f_name2,"%d.txt",n_file-i-1);
        merge_two(f_name1,f_name2,"tmp.txt");
        char cmd[100];
        sprintf(cmd,"del %s",f_name1);
        system(cmd);
        if(n_file!=2)
            sprintf(cmd,"ren %s %s","tmp.txt",f_name1);
        else
            sprintf(cmd,"ren %s %s","tmp.txt","result.txt");
        system(cmd);
    }
    merge_all(n_file/2+n_file%2);
}

//删除临时文件
void del_tmp_file(int n_file){
    for(int i=1;i<n_file;++i){
        char f_name[20];
        sprintf(f_name,"%d.txt",i);
        char cmd[100];
        sprintf(cmd,"del %s",f_name);
        system(cmd);
    }
}

void outer_sort(char* file_path,int n){
    int n_file=divi_file(file_path,n);
    if(n_file==0)
        return;
    cout<<n_file<<endl;
    in_sort(n_file);
    merge_all(n_file);
    del_tmp_file(n_file);
}

 多路归并时,需要维护一棵败者树来快速查找出多路之中的最小值。见下一篇随笔。

 

posted @ 2013-06-14 10:03  iyjhabc  阅读(406)  评论(0编辑  收藏  举报