外部排序 多路合并

《数据结构与算法分析——C语言描述》  第七章


这个还是挺有意思的,用很少的内存空间给很多的数排序,复杂度是logk(N/M)



#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<queue>
//#include"fatal.h"
#define M 3
#define K 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);
}

FILE* file[2 * K];//文件指针数组
char name[200];//生成的名字
int runlen;//顺序串长度

void write(int *a, int n, FILE *out) {
	for (int i = 0; i < n; i++) {
		fprintf(out, "%d ", a[i]);
	}
}


char* fileName(char *buf, int part, int i) {
	if (part == 0)
		strcpy(buf, "ta");
	else
		strcpy(buf, "tb");
	char num[5];
	strcat(buf, itoa(i + 1, num, 10));
	return buf;
}

void open(int part, char* type) {//打开文件
	if (part == 0) {
		for (int i = 0; i < K; i++) {
			file[i] = fopen(fileName(name, part, i), type);
		}
	}
	else {
		for (int i = 0; i < K; i++) {
			file[K + i] = fopen(fileName(name, part, i), type);
		}
	}

}



void close(int part) {//关闭文件
	if (part == 0)
		for (int i = 0; i < K; i++)
			fclose(file[i]);
	else
		for (int i = 0; i < K; i++)
			fclose(file[K + i]);
}

int isAllEnd(int readPart) {//读取的文件是否全部都读完了
	for (int i = 0; i < K; i++)
		if (!feof(file[readPart*K + i]))
			return 0;
	return 1;
}

int isAllBiggerThanRunLen(int * cursor) {
	for (int i = 0; i < K; i++) {
		if (cursor[i] < runlen)
			return 0;
	}
	return 1;
}


typedef std::pair<int, int> Pair_int;
auto cmp = [](const Pair_int& left, const Pair_int& right) { return (left.first) > (right.first); };//lambda表达式,算是一种比较精简的函数吧


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;
	}
}

#define N 222


void writeRandIntToFile() {
	int a[N];
	getRandomInt(a, N);
	FILE *fp = fopen("ta1", "w");
	for (int &i : a)
		fprintf(fp, "%d ", i);
	fclose(fp);
}

int main() {

	
	writeRandIntToFile();

	int max_memory[M];

	//初始化顺序串

	FILE *ta1 = fopen("ta1", "r");
	open(1, "w");
	int n = 0;
	int writeNum = 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……
		write(max_memory, readNum, file[K + writeNum]);
		writeNum = (writeNum + 1) % K;
	}
	fclose(ta1);
	close(1);

	//K路排序
	runlen = M;
	int readpart = 1;//0表示ta1,ta2,1表示tb1,tb2
	while (runlen < n) {
		if (readpart == 1) {
			open(0, "w");
			open(1, "r");
		}
		else {
			open(0, "r");
			open(1, "w");
		}
		writeNum = 0;//写到哪,一半中的 第一个磁盘还是第二个磁盘
		while (!isAllEnd(readpart)) {
			int cursor[K];
			memset(cursor, 0, sizeof(cursor));


			int num;
			int isHasNumNoWrite[K];//0表示目前没有缓存数字
			memset(isHasNumNoWrite, 0, sizeof(isHasNumNoWrite));
			int writePart = readpart == 0 ? 1 : 0;
			std::priority_queue<Pair_int, std::vector<Pair_int>, decltype(cmp)> h(cmp);
			while (!isAllBiggerThanRunLen(cursor)) {//分别取出K个顺序串合并
				int isInsertNew = 0;
				for (int i = 0; i < K; i++) {
					if (isHasNumNoWrite[i] == 0 && !feof(file[readpart*K + i]) && cursor[i] < runlen) {
						if (fscanf(file[readpart*K + i], "%d", &num) == 1) {
							isHasNumNoWrite[i] = 1;
							h.push({ num,i });
							isInsertNew = 1;
						}

					}

				}
				if (isInsertNew == 0 && h.empty())//这里可是细节,这个最后只剩下空格没有数字的话也不算文件结尾,feof返回0
					break;
				Pair_int p = h.top();
				h.pop();
				fprintf(file[writePart*K + writeNum], "%d ", p.first);
				cursor[p.second]++;
				isHasNumNoWrite[p.second] = 0;
			}
			writeNum = (writeNum + 1) % K;
		}
		close(0);
		close(1);
		runlen *= K;
		readpart = (readpart == 0) ? 1 : 0;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值