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