http://www.cnblogs.com/uvsjoh/archive/2012/03/24/2415343.html
在某些應用中,因爲內存資源有限制,而要排序的文件很大(比如10G的文件,只有10M的內存)主要的思想是:1 分割文件,使分割的文件能全部加載到內存。2 分別排序每一個分割的文件3 合併文件 難的是合併操作1 跌增合併,一次合併兩個文件。依次類推,直到最終只剩一個文件。時間複雜度主要在讀取文件,要多次讀取。2 利用堆,一次合併多個文件 時間複雜度主要取決於堆的查找。(堆主要用於查找當前最小的行) 或者更直接的是,每次順序查找當前內存中的最小行。 一般而言內存訪問速度要快很多,因此第2中方法應該快很多。如下是一個簡單的window上的實現:
//單行最大長度lEN_LINE - 1 #define LEN_LINE 80 int cmp(const void * str1, const void *str2) { const char *p1 = (char *)str1, *p2 = (char *)str2; return strcmp(p1, p2); } /* 文本文件以行爲單位排序 */ bool FileSort(const char *file, size_t memLimit) { FILE *fp; fp = fopen(file, "r"); fseek(fp, 0, SEEK_END); size_t file_size = ftell(fp); fseek(fp, 0, SEEK_SET); size_t split_cnt = (file_size+memLimit-1)/memLimit; char prefix[256] = "tttt"; char file_t[256]; int fileNo; //臨時文件編號 char *buff = new char[memLimit]; if (buff == NULL) return false; size_t totalReadLen=0; //已讀文件大小 size_t lineCnt = memLimit/LEN_LINE; //分配的空間能存下的行數 fileNo = 1; //分割文件並排序 while (totalReadLen < file_size) { //生成一個臨時文件名 sprintf(file_t, "%s%d.txt", prefix, fileNo); FILE *fp_t = fopen(file_t, "w"); size_t read_len=0; int i=0; //按行讀取 while ( (i<lineCnt) && fgets(buff+read_len, LEN_LINE, fp)) { i++; totalReadLen += strlen(buff+read_len)+1; //算上回車 read_len += LEN_LINE; } //排序 qsort(buff, i, LEN_LINE, cmp); int j=0; read_len = 0; //寫入文件 while (j < i) { fputs(buff+read_len, fp_t); j++; read_len += LEN_LINE; } fclose(fp_t); fileNo++; } fclose(fp); fp = fopen(file, "w"); FILE **fp_t = (FILE **)malloc(sizeof(FILE *)*fileNo); bool *flg = new bool[fileNo]; //標識是否該從相應文件中讀取新的一行 fileNo--; for (int i=1; i<=fileNo; i++) { sprintf(file_t, "%s%d.txt", prefix, i); fp_t[i-1] = fopen(file_t, "r"); flg[i-1] = true; } //合併 while (1) { //讀取新的一行 for (int i=0; i<fileNo; i++) { if (flg[i] ) { if (fp_t[i]) { if (!fgets(buff+i*LEN_LINE, LEN_LINE, fp_t[i])) { fclose(fp_t[i]); sprintf(file_t, "%s%d.txt", prefix, i); DeleteFile(file_t); buff[i*LEN_LINE] = 0; fp_t[i] = NULL; } } flg[i] = false; } } int min = 0; //找出當前最小的行 for (i=1; i<fileNo; i++) { if (buff[min*LEN_LINE] == 0) min = i; else if (buff[i*LEN_LINE] && strcmp(buff+min*LEN_LINE, buff+i*LEN_LINE)>0) min = i; } if (buff[min*LEN_LINE]) { fputs(buff+min*LEN_LINE, fp); flg[min] = true; } else break; } fclose(fp); return true; }