当排序内容太大,不足以全部放入内存进行内部排序,则可把排序内容按可用内存大小分割成多个文件,分别读取文件进行内排,排序结果继续写入文件。最后对所有文件进行归并排序合并成有序大文件。
外部排序步骤: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); }
多路归并时,需要维护一棵败者树来快速查找出多路之中的最小值。见下一篇随笔。