《数据结构与算法分析——C语言描述》 第七章
#include <stdio.h>
#include<queue>
#include"fatal.h"
#define M 3//最大的内存
#define N 33//要排序的数字量,1—N
typedef int ElementType;
char name[200];//生成的名字
std::queue<int> notHandleFile;
std::queue<int> nullFile;
char* fileName(char *buf, int i) {
strcpy(buf, "T");
char num[5];
strcat(buf, _itoa(i + 1, num, 10));
return buf;
}
int RandInt(int i, int j) {
int temp;
temp = (int)(i + (1.0*rand() / RAND_MAX)*(j - i));
return temp;
}
void getRandomInt(int *A, int n) {
for (int i = 0; i < n; i++) {
A[i] = i + 1;
}
for (int i = 1; i < n; i++) {
//std::swap(A[i], A[RandInt(0, i)]);
int randAdrr = RandInt(0, i);
int t = A[i];
A[i] = A[randAdrr];
A[randAdrr] = t;
}
}
void writeRandIntToFile() {
int a[N];
getRandomInt(a, N);
FILE *fp = fopen("ta1", "w");
for (int &i : a)
fprintf(fp, "%d ", i);
fclose(fp);
}
#define leftChild(i) (2*(i)+1) //下标从0开始
void percDown(int *a, int i, int n) {
int child = leftChild(i);
int temp;
for (temp = a[i]; leftChild(i) < n; i = child) {
child = leftChild(i);
if (child != n - 1 && a[child] > a[child + 1])
child++;
if (temp > a[child])
a[i] = a[child];
else
break;
}
a[i] = temp;
}
void buildHeap(int *arr, int n) {
for (int i = (n - 1 - 1) / 2; i >= 0; i--) {
percDown(arr, i, n);
}
}
void insertHeap(int *arr, int &n) {
int i;
int X = arr[n];
n++;
for (i = n - 1; i > 0 && arr[(i - 1) / 2] > X; i = (i - 1) / 2)//下表为0的时候就是根节点,不用上滤了
arr[i] = arr[(i - 1) / 2];
arr[i] = X;
}
int deleteMin(int *arr, int &n) {//n为数量
int i, child;
ElementType minElement, lastElement;
minElement = arr[0];
lastElement = arr[n - 1];//删除右下的元素
n--;
for (i = 0; i <n; i = child) {
child = leftChild(i);
if (child >= n)//这个用于在最底层的时候,获得的儿子是越界的,此时i是上一次迭代的child,child两儿子中的最小值
break;
if (child != n - 1 && arr[child] > arr[child + 1]) {//不一定有两个儿子
child++;
}
if (lastElement > arr[child])
arr[i] = arr[child];
else
break;
}
arr[i] = lastElement;
return minElement;
}
void initRun(char *inputFileName) {
FILE* readFp = fopen(inputFileName, "r");
if (readFp == NULL)
Error("OPEN FILE FAILED");
int fileNum = 0;//文件数量
int arr[M];//二叉堆的数组
int size = 0;//有效数字个数
int deadSpace = M - 1;//死区下标
while (size < M && fscanf(readFp, "%d", &arr[size]) == 1) {//读入数字初始化堆
size++;
}
do {
FILE *writeFile = fopen(fileName(name, fileNum), "w");
buildHeap(arr, size);
while (size != 0) {//堆不是空
int min = deleteMin(arr, size);
fprintf(writeFile, "%d ", min);
if (fscanf(readFp, "%d", &arr[deadSpace]) == 1) {//输出了一个数,再读取一个数
if (arr[deadSpace]>min) {//放到堆中
insertHeap(arr, size);//此时size和deadSize是相同的
}
else {//放到死区中
deadSpace--;
}
}
}
fclose(writeFile);
notHandleFile.push(fileNum);
fileNum++;//下一个串
size = M - 1 - deadSpace;//求死区中元素的数量
deadSpace = M - 1;//初始化死区下标
if (size > 0 && size<M) {//当死区元素没填满的时候从右边移动到左边
for (int i = 0; i < size; i++) {
arr[i] = arr[i + M - size];
}
}
} while (!feof(readFp));
nullFile.push(fileNum);
}
void mergeRun(int file1, int file2, int writefile) {
FILE *readFp1 = fopen(fileName(name, file1),"r");
FILE *readFp2 = fopen(fileName(name, file2), "r");
FILE *writeFp = fopen(fileName(name, writefile), "w");
int a, b;
int hasNum1 = 0, hasNum2 = 0;
while ((hasNum1==1||fscanf(readFp1, "%d", &a)==1)&& (hasNum2 == 1 || fscanf(readFp2, "%d", &b) == 1)) {
hasNum1 = 1;
hasNum2 = 1;
if (a < b) {
fprintf(writeFp, "%d ", a);
hasNum1 = 0;
}
else {
fprintf(writeFp, "%d ", b);
hasNum2 = 0;
}
}
while ((hasNum1 == 1 || fscanf(readFp1, "%d", &a) == 1)) {
fprintf(writeFp, "%d ", a);
hasNum1 = 0;
}
while (hasNum2 == 1 || fscanf(readFp2, "%d", &b) == 1) {
fprintf(writeFp, "%d ", b);
hasNum2 = 0;
}
fclose(readFp1);
fclose(readFp2);
fclose(writeFp);
}
int main() {
writeRandIntToFile();
char inputFileName[20] = "ta1";//要排序的文件
//scanf("%s", inputFileName);
initRun(inputFileName);//初始化顺序串
int cnt = 0;
while (notHandleFile.size() > 1) {
int file1 = notHandleFile.front();
notHandleFile.pop();
int file2 = notHandleFile.front();
notHandleFile.pop();
int writeFile = nullFile.front();
nullFile.pop();
mergeRun(file1, file2, writeFile);
nullFile.push(file1);
nullFile.push(file2);
notHandleFile.push(writeFile);
}
}