基于磁盘的带替换选择的合并排序

1)问题描述和分析

我们计算机的内存是有限的,当我们需要处理的数据超出我们的内存的时候就需要我们借助磁盘来进行排序,这种排序被称为外部排序,外部排序通常由归并排序实现.

2)设计与实现

我们将所需要处理的数据放入存入txt文件,假设要处理50000个数据,将这些数据分为100个文件,每个文件500个数据,利用内部排序使这些文件中的数据有序,之后利用队列对这些数据进行归并排序.

3)测试例子与结果分析

排序前的部分数据为:

利用随机数生成50000个数据

排序后的部分数据为:

 4)源代码

#include<stdio.h>
#include<stdlib.h>
#define ROOT   "C:\\Users\\HP\\Desktop\\新建文件夹"    //根目录 
#define N 100   //文件总个数 
typedef struct{//创建一个双向循环队列保存结点 
	FILE *f;
	 struct Node *next;
	 struct Node *pre; 
}Node; 
Node *initQueue(){
	Node *head=(Node*)malloc(sizeof(Node));
	head->f=NULL;
	head->next=NULL;
	head->pre=NULL;
	Node *p=head;//保存尾结点 
	int i;
	for(i=0;i<N;i++){//循环创造结点 
		Node *temp=(Node*)malloc(sizeof(Node));
		char name[99];
		sprintf(name,"%s\\%d.txt",ROOT,i);//设置文件名称 
		temp->f=fopen(name,"a+");
		temp->next=p;
		head->next=temp;
		temp->pre=head;
		p->pre=temp;
		head=temp;
	}
	return p;//返回头结点 
}
FILE *  merge(FILE *r,FILE *y,int n)//传入要排序的两个文件指针 //进行一次归并排序 
{
	char name[99];
	sprintf(name,"%s\\file%d.txt",ROOT,n);//设置文件夹名字 
	FILE *p=fopen(name,"a+");
	int i,j;
	int tempr,tempy;
	tempr=fscanf(r,"%d",&i);//文件结尾标志 
	tempy=fscanf(y,"%d",&j);
	while(tempr>0&&tempy>0){//判断是否到文件结尾 
		if(i<j){
			fprintf(p,"%d ",i);//将i放入文件 
			tempr=fscanf(r,"%d",&i);
		}
		else{
			fprintf(p,"%d ",j);//将j放入文件 
			tempy=fscanf(y,"%d",&j);
		}
	}
	if(tempr>0){
	fprintf(p,"%d ",i);
	while(fscanf(r,"%d",&i)>0)fprintf(p,"%d ",i);
	}//将剩下的数字传入文件 
	else if(tempy>0){
	fprintf(p,"%d ",j);
	while(fscanf(y,"%d",&j)>0)fprintf(p,"%d ",j);
}
	rewind(p);//重新指向函数头 
	return p;
 } 
FILE * mergesort(){
 	Node *head=initQueue();//初始化队列 
 	Node *p=head->next;//p是第一个节点 
 	int flag=0;//记录文件数量 
 	while(p->next!=head){//当队列中仅有一个结点时退出循环 
 		Node* temp=(Node*)malloc(sizeof(Node));
 		Node *t=p->next;
 		temp->f=merge(p->f,t->f,flag);
 		flag++; 
 		temp->next=head;//排序后的结点加在队列后 
 		temp->pre=head->pre;
 		Node *prep=temp->pre;
 		prep->next=temp;
 		head->pre=temp;
 		prep=p->next;
 		head->next=prep->next;//将排序前的两个结点删除 
 		p=head->next;//更新p 
 		p->pre=head;
 		
	 }
 	return p->f;
 }
 
 void CreatFile(FILE *f){//将一个大文件分成若干个小文件 
 	int i;
	int num;
	for(i=0;i<N;i++)
	{
		int j;
		int flag=1;
		FILE *temp;
		char name[99];
		sprintf(name,"%s\\%d.txt",ROOT,i);//设置文件名称 
		temp=fopen(name,"a+");
		int arr[500];
		for(j=0;j<500;j++){
			if(fscanf(f,"%d",&num)>0)
			arr[j]=num;
			//fprintf(temp,"%d ",num);//每500个一个文件 
			else {
				flag=0;
				break;
			}
		}
		int fi,fj;
		for(fi=0;fi<499;fi++){
			for(fj=0;fj<499-fi;fj++){
				if(arr[fj]>arr[fj+1]){
					int temp=arr[fj];
					arr[fj]=arr[fj+1];
					arr[fj+1]=temp;
				}
			}
		}
		if(flag==0)break;
		for(fj=0;fj<500;fj++){
			fprintf(temp,"%d ",arr[fj]);
		}
		fclose(temp);
		}
 }
 FILE* Textdata(){
 	FILE *f=fopen("C:\\Users\\HP\\Desktop\\新建文件夹\\text.txt","a+");
 	int i;
 	for(i=0;i<50000;i++)fprintf(f,"%d ",rand());
 	rewind(f);
return f;
 } 
 int main(){
	FILE *p=Textdata();
	CreatFile(p);
	p=mergesort();
		return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值