《数据结构与算法分析——C语言描述》 第七章
外部排序简单算法
虽然是用了归并,涉及到文件,还是挺麻烦的。文件读取之后是不用fseek的话是不能返回的,并且文件我是用文本储存数字,每个数字的字符长度不一样,不能像数组那样随机读取存放,只能一个一个的读。
#include <stdio.h> #include <stdlib.h> //#include"fatal.h" #define M 3 typedef int ElementType; void insertionSort(int *a, int n) { int j, p; int temp; for (p = 1; p < n; p++) { temp = a[p]; for (j = p; j > 0 && temp < a[j - 1]; j--) a[j] = a[j - 1]; a[j] = temp; } } void swap_my(ElementType *a, ElementType *b) { ElementType temp; temp = *a; *a = *b; *b = temp; } ElementType median3(ElementType a[], int left, int right) { int center = (left + right) / 2; if (a[left] > a[center]) swap_my(&a[left], &a[center]); if (a[left] > a[right]) swap_my(&a[left], &a[right]); if (a[center] > a[right]) swap_my(&a[center], &a[right]); swap_my(&a[center], &a[right - 1]); return a[right - 1]; } #define CUTOFF (3) void qsort_my(ElementType a[], int left, int right) { if (left + CUTOFF <= right) { int i, j; ElementType pivot; pivot = median3(a, left, right); i = left; j = right - 1; while (1) { while (a[++i] < pivot) {} while (a[--j] > pivot) {} if (i < j) swap_my(&a[i], &a[j]); else break; } swap_my(&a[i], &a[right - 1]); qsort_my(a, left, i - 1); qsort_my(a, i + 1, right); } else insertionSort(a + left, right - left + 1); } void quickSort_my(ElementType a[], int n) { qsort_my(a, 0, n - 1); } void write(int *a, int n, FILE *out) { for (int i = 0; i < n; i++) { fprintf(out, "%d ", a[i]); } } int main() { FILE *ta1, *tb1, *tb2; int max_memory[M]; //ta2 = fopen("ta2", "r+"); //初始化顺序串 ta1 = fopen("ta1", "r+"); tb1 = fopen("tb1", "w"); tb2 = fopen("tb2", "w"); int n = 0; int whereToWrite = 0;//0表示tb1,1表示tb2 while (!feof(ta1)) { int readNum = 0; while (readNum < M && fscanf(ta1, "%d", &max_memory[readNum]) != EOF) { n++; readNum++; } quickSort_my(max_memory, readNum); //交替写到tb1或写到tb2 if (whereToWrite == 0) write(max_memory, readNum, tb1); else write(max_memory, readNum, tb2); whereToWrite = whereToWrite == 0 ? 1 : 0; } fclose(ta1); fclose(tb1); fclose(tb2); int runLen = M; int whereToRead = 1;//0表示ta1,ta2,1表示tb1,tb2 while (runLen < n) { FILE* file[4]; if (whereToRead == 1) { file[0] = fopen("tb1", "r"); file[1] = fopen("tb2", "r"); file[2] = fopen("ta1", "w"); file[3] = fopen("ta2", "w"); } else { file[0] = fopen("ta1", "r"); file[1] = fopen("ta2", "r"); file[2] = fopen("tb1", "w"); file[3] = fopen("tb2", "w"); } whereToWrite = 0;//写到哪,要写的两个磁盘中的 第一个磁盘还是第二个磁盘 int end1 = 0, end2 = 0;//要读的文件的 第一个地盘 第二个磁盘 是否结尾 while (!end1 || !end2) { int i = 0, j = 0; int a, b; int isHasNumNotWrite1 = 0, isHasNumNotWrite2 = 0;//0表示目前没有缓存数字 while (i < runLen && j < runLen) {//分别取出两个顺序串 if (isHasNumNotWrite1 == 0) { if (fscanf(file[0], "%d", &a) == 1)//成功读入 { isHasNumNotWrite1 = 1; } else { end1 = 1;//读完了 break; } } if (isHasNumNotWrite2 == 0) { if (fscanf(file[1], "%d", &b) == 1) { isHasNumNotWrite2 = 1; } else { end2 = 1; break; } } if (a < b) { fprintf(file[2 + whereToWrite], "%d ", a); i++; isHasNumNotWrite1 = 0; } else { fprintf(file[2 + whereToWrite], "%d ", b); j++; isHasNumNotWrite2 = 0; } } ; //有可能是成功读入、满了未填满、中途break while (end1 == 0 && i < runLen) { if (isHasNumNotWrite1 == 0) { if (fscanf(file[0], "%d", &a) == 1) isHasNumNotWrite1 = 1; else { end1 = 1; break;//必须break,此时没有缓冲数字,也不能读进新的数字,不可以写入 } } fprintf(file[2 + whereToWrite], "%d ", a); isHasNumNotWrite1 = 0; i++; } while (end2 == 0 && j < runLen) { if (isHasNumNotWrite2 == 0) { if (fscanf(file[1], "%d", &b) == 1) { isHasNumNotWrite2 = 1; } else { end2 = 1; break; } } fprintf(file[2 + whereToWrite], "%d ", b); isHasNumNotWrite2 = 0; j++; } whereToWrite = whereToWrite == 0 ? 1 : 0; } for (int i = 0; i < 4; i++) fclose(file[i]); runLen *= 2; whereToRead = (whereToRead == 0) ? 1 : 0; } }