外排序的实现
- 思想
- 代码分析
- 完整代码
如果有海量数据需要排序,而在内存中放不下这么多数据,因此就不能使用内排序(直接插入排序,希尔排序,堆排序,快速排序,归并排序等等)。关于想了解这些内排序的请看这里各种排序的实现,所以我们只能使用外排序,来把我们海量数据排好序,
思想
外排序,我们需要采用归并排序的思想来实现这个过程。
 
因此我们最终思想是这样的
 
代码分析
要学会写外排序的代码,需要把文件学好,想了解文件的请看这里文件
假设文件里有100个数据
 生成1-100个随机数放在文件里
#define N 100
void CreteartFile(const char* filename)
{
	srand((unsigned int)time(NULL));
	//生成一个随机数1-100的文件
	FILE* pf = fopen(filename, "w");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}
	for (int i = 0; i < N; ++i)
	{
		fprintf(pf, "%d ", rand() % 100 + 1);
	}
	fclose(pf);
}
int  main()
{
	
	
	const char* filename = "Sort.txt";
	CreteartFile(filename);
	//外排序
	MerSortFile(filename);
	return 0;
}
把文件平均分成若干个有序的小文件
我们有一个100个数的文件
 把这个文件平均分成10个小文件,每个小文件放10个数。
 为了使这些小文件的数据有序,因此我们在大文件里取出数据,放在数组a中,只要数组a里的数据达到10个。就对数组a使用快排(假设内存可以一次放得下这么数据),直到取完文件中的数据。
//外排序
void MerSortFile(const char* filename)
{
	//取数据,把一个文件分成若干个有序的小文件
	FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		return;
	}
	int a[10] = { 0 };
	int value = 0;
	int i = 0;
	int n = 10;
	//存放小文件名称
	char fsubename[10] = { 0 };
	int fnumeber = 0;
	//从文件中取出数据
	while (fscanf(fout, "%d", &value) != EOF)
	{
		//一个小文件放10个数据
		if (i < n-1)
		{
			a[i++] = value;
		}
		else
		{
		//这里是特殊处理,下面画图有解释
			a[i] = value;
			//对a数组排序
			QuickSort(a, 0, n - 1);
			//创建小文件,并将a写到小文件里
			sprintf(fsubename, "%d.txt", ++fnumeber);
			FILE* fin = fopen(fsubename, "w");
			if (fin == NULL)
			{
				perror("fopen fail");
				return;
			}
			//写数据
			for (int i = 0; i < n; ++i)
			{
				fprintf(fin, "%d ", a[i]);
			}
			fclose(fin);
			i = 0;
		}
	}
	fclose(fout);
}

 两两归并小文件,直到归并成一个文件
//外排序
void MerSortFile(const char* filename)
{
	//取数据,把一个文件分成若干个有序的小文件
	FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		return;
	}
	int a[10] = { 0 };
	int value = 0;
	int i = 0;
	int n = 10;
	char fsubename[10] = { 0 };
	int fnumeber = 0;
	while (fscanf(fout, "%d", &value) != EOF)
	{
		//一个小文件放10个数据
		if (i < n-1)
		{
			a[i++] = value;
		}
		else
		{
			a[i] = value;
			//对a数组排序
			QuickSort(a, 0, n - 1);
			//创建小文件,并将a写到小文件里
			sprintf(fsubename, "%d.txt", ++fnumeber);
			FILE* fin = fopen(fsubename, "w");
			if (fin == NULL)
			{
				perror("fopen fail");
				return;
			}
			//写数据
			for (int i = 0; i < n; ++i)
			{
				fprintf(fin, "%d ", a[i]);
			}
			fclose(fin);
			i = 0;
		}
	}
	//归并小文件,直到整体归成一个有序的完整文件
	//这一块逻辑看下图分析
	char mfile[20] = "12";
	char file1[20] = "1.txt";
	char file2[20] = { 0 };
	for (int i = 2; i <= n; ++i)
	{
		sprintf(file2, "%d.txt", i);
		_MergerFile(mfile, file1, file2);
		//迭代,file1存储mfile名
		strcpy(file1, mfile);
		//mfile存储下一次两个文件要归并在一起的文件名
		sprintf(mfile, "%s%d", mfile, i+1);
	}
	fclose(fout);
}

 两个小文件归并过程
void _MergerFile(const char* mfile,const char* file1,const char* file2)
{
	FILE* fin = fopen(mfile, "w");
	if (fin == NULL)
	{
		perror("fopen fail");
		return;
	}
	FILE* fout1 = fopen(file1, "r");
	if (fout1 == NULL)
	{
		perror("fopen fail");
		return;
	}
	FILE* fout2 = fopen(file2, "r");
	if (fout2 == NULL)
	{
		perror("fopen fail");
		return;
	}
	int num1 = 0;
	int num2 = 0;
//这里也是对文件指针的特殊处理,看下图
	int ret1 = fscanf(fout1, "%d", &num1);
	int ret2 = fscanf(fout2, "%d", &num2);
	while (ret1 != EOF && ret2 != EOF)
	{
		if (num1 < num2)
		{
			fprintf(fin, "%d ", num1);
			ret1= fscanf(fout1, "%d", &num1);
		}
		else
		{
			fprintf(fin, "%d ", num2);
			ret2 = fscanf(fout2, "%d", &num2);
		}
	}
	while (ret1 != EOF)
	{
		fprintf(fin, "%d ", num1);
		ret1 = fscanf(fout1, "%d", &num1);
	}
	while (ret2 != EOF)
	{
		fprintf(fin, "%d ", num2);
		ret2 = fscanf(fout2, "%d", &num2);
	}
	fclose(fin);
	fclose(fout1);
	fclose(fout2);
}

完整代码
//合并小文件
void _MergerFile(const char* mfile,const char* file1,const char* file2)
{
	FILE* fin = fopen(mfile, "w");
	if (fin == NULL)
	{
		perror("fopen fail");
		return;
	}
	FILE* fout1 = fopen(file1, "r");
	if (fout1 == NULL)
	{
		perror("fopen fail");
		return;
	}
	FILE* fout2 = fopen(file2, "r");
	if (fout2 == NULL)
	{
		perror("fopen fail");
		return;
	}
	int num1 = 0;
	int num2 = 0;
	int ret1 = fscanf(fout1, "%d", &num1);
	int ret2 = fscanf(fout2, "%d", &num2);
	while (ret1 != EOF && ret2 != EOF)
	{
		if (num1 < num2)
		{
			fprintf(fin, "%d ", num1);
			ret1= fscanf(fout1, "%d", &num1);
		}
		else
		{
			fprintf(fin, "%d ", num2);
			ret2 = fscanf(fout2, "%d", &num2);
		}
	}
	while (ret1 != EOF)
	{
		fprintf(fin, "%d ", num1);
		ret1 = fscanf(fout1, "%d", &num1);
	}
	while (ret2 != EOF)
	{
		fprintf(fin, "%d ", num2);
		ret2 = fscanf(fout2, "%d", &num2);
	}
	fclose(fin);
	fclose(fout1);
	fclose(fout2);
}
//外排序
void MerSortFile(const char* filename)
{
	//取数据,把一个文件分成若干个有序的小文件
	FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		return;
	}
	int a[10] = { 0 };
	int value = 0;
	int i = 0;
	int n = 10;
	char fsubename[10] = { 0 };
	int fnumeber = 0;
	while (fscanf(fout, "%d", &value) != EOF)
	{
		//一个小文件放10个数据
		if (i < n-1)
		{
			a[i++] = value;
		}
		else
		{
			a[i] = value;
			//对a数组排序
			QuickSort(a, 0, n - 1);
			//创建小文件,并将a写到小文件里
			sprintf(fsubename, "%d.txt", ++fnumeber);
			FILE* fin = fopen(fsubename, "w");
			if (fin == NULL)
			{
				perror("fopen fail");
				return;
			}
			//写数据
			for (int i = 0; i < n; ++i)
			{
				fprintf(fin, "%d ", a[i]);
			}
			fclose(fin);
			i = 0;
		}
	}
	//归并小文件,直到整体归成一个有序的完整文件
	char mfile[20] = "12";
	char file1[20] = "1.txt";
	char file2[20] = { 0 };
	for (int i = 2; i <= n; ++i)
	{
		sprintf(file2, "%d.txt", i);
		_MergerFile(mfile, file1, file2);
		strcpy(file1, mfile);
		sprintf(mfile, "%s%d", mfile, i+1);
	}
	fclose(fout);
}















