《数据结构与算法分析——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;
}
}