⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 out_sort.c

📁 外部排序程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	  * outstu为缓冲区,结构合seg相同
	  *seg为内存段
	  k为那个段
	  flag=0是正常输出,=1是直接末尾全部输出。
  */
void output_ex(pSORT_TEMP_FILE newfiles,int newf,pSEG_MEM outbuf,pSEG_MEM seg,\
			   int k,int flag){

    if(flag==1){
        fwrite((*outbuf).buf,dbfHead.record_length,(*outbuf).inrows,newfiles[newf].f);
		(*outbuf).inrows=0;
		(*outbuf).allrows=0;
    }else{
    	if((*outbuf).inrows==(*outbuf).allrows){ //输出文件
            fwrite((*outbuf).buf,dbfHead.record_length,(*outbuf).inrows,newfiles[newf].f);
	    	(*outbuf).inrows=0;
	    	//(*outbuf).allrows=0;
		}
    	//从第k个归并段,输入到缓冲区。
        memcpy((*outbuf).buf+(*outbuf).inrows*dbfHead.record_length,\
		       seg[k].buf+(seg[k].inrows-1)*dbfHead.record_length,\
               dbfHead.record_length);

    	(*outbuf).inrows++;
	}
}

/*
 *功能:K路归并排序算法,字符型
 *K路归并程序,利用败者树ls将编号从0到k-1的k个输入
 *归并段中的记录归并到输出归并段 b[0]到b[k-1]为败者
 *树上的k个叶子结点,分别存放k个输入归并段中当前记录
 *的关键码。
 *参数:
 *      * infiles是合并文件参数
 *      * newfiles是合并以后文件结构
 *      newf是输出文件索引
 *      *ls为失败树
 *      *b为合并排序segment各段关键字
 *      k为路数
 */

void K_Merge(pSORT_TEMP_FILE infiles,pSORT_TEMP_FILE  newfiles,int newf,\
			 pSEG_MEM seg,pSEG_MEM outbuf,pLoserTree ls,pExNode b,int k)
{
   int q=0; 
   int i;
   for(i=0;i<k;i++) input_ex(infiles,seg,b,i);    //初始化从0 ---k-1           
   CreateLoserTree(ls,b,k);                                         
   while( strcmp(b[ls[0].element].key,MAXKEY)!=0 ){ 
       q=ls[0].element;                                     
       output_ex(newfiles,newf,outbuf,seg,q,0);   
       input_ex(infiles,seg,b,q); 
       Adjust(ls,b,k,q);     
   }
   output_ex(newfiles,newf,outbuf,seg,q,1);                                  
}

/*
功能:输入文件名字进行k路合并排序,输出到指定文件
      合并排序是递归过程。数个文件进,一个文件出,
	  文件名依次后缀。在unix系统中使用并行进程。
	  返回-1失败,0成功。此函数是一个递归函数
      合并方法是先将快速排序文件k路合并存放在第1次
	  合并排序结构文件中全部完成以后,然后合并第一次
	  文件生成第二次的文件,依次。

参数:infiles是当前排序文件
      outfiles输出文件
	  merge_k 是当前路数
  */
int merge_sort(SORT_TEMP_FILE * infiles,char * outfiles,int merge_k,\
			   DBF_FILE_ALL_FIELD allf){
    SEG_MEM    seg[MERGE_K_MAX];            //段的内存指针
	SEG_MEM    outbuf;                      //输出缓冲结构
	int        part=0;                      //几个大段,每个包含MERGE_K_MAX个segment
	ExNode     exc[MERGE_K_MAX];            //字符型
	LoserTree  ls[MERGE_K_MAX];             //字符型败者树是完全二叉树且不含叶子,
	                                        //可采用顺序存储结构
    SORT_TEMP_FILE  newfiles[SORT_FILE_MAX];  //生成的新的文件
#ifdef UNIX
    int        nowpa=0;                     //当前并行度
	pid_t      pid;                         //进程号
    int        process=0;
#endif
	int pa=0;
	int k=0,v=0,l=0;
	char tmppix1[10]="";
	char tmppix2[10]="";
	int  mergek=0;
	unsigned long rec_num=0;

    if(infiles==NULL){
		printf("infile or outfile in marge is null");
		return -1;
	}

	//最终已经生成了文件了
	if(infiles[0].max==1){
		strcpy(outfiles,infiles[0].file);
		return 0;
	}

	if(infiles[0].max%merge_k==0){
        part=(int)(infiles[0].max/merge_k);
	}else{
        part=(int)(infiles[0].max/merge_k)+1;
	}

	for(pa=0;pa<part;pa++){    //pa值可以当作输出newfiles文件数。
        //输出文件,递归调用的输入文件,文件分配,
		//完了以后关闭,递归调用的时候再打开。
#ifdef UNIX
		now_process++;
		process++;

		if(process>=MAX_PROCESS){
			printf("open too many process than %d and exit \n",MAX_PROCESS);
			exit(1);
		}
        if(pid=fork()<0){
              printf("fork process error");
			  if(pa!=0){pa--;now_process--;} //不成功重新开进程。
	    	  continue;
		}else if(pid==0){   //父进程
			  nowpa++;
			 // parallel_all++;
			  if(parallel_num==nowpa){
				  for(v=0;v<nowpa;v++){
					  wait(NULL);
				  }
				  nowpa=0;  //当前并行度重新置0
			  }
			  continue;  //父进程跳转到for开头。

		}else{
#endif
	    //并行系统中是子进程。
        itoa(golfileId,tmppix1,10);
		strcpy(newfiles[pa].file,argsg);
		strcat(newfiles[pa].file,tmppix1);
        itoa(pa,tmppix2,10);
		strcat(newfiles[pa].file,tmppix2);
		strcat(newfiles[pa].file+strlen(argsg)+strlen(tmppix1)+strlen(tmppix2),".dbf");  
		
		if((newfiles[pa].f=openAFile(newfiles[pa].file,"w+b"))==NULL){
			printf("open file %s failed",newfiles[k].file);
			return -1;
		}
        newfiles[pa].fileid=pa;
        newfiles[pa].max=part;  

		if((outbuf.buf=malloc(OUT_BUFF*dbfHead.record_length))==NULL){
			printf("malloc in merge sort error");
			return -1;
		}
        outbuf.allrows=OUT_BUFF;
		outbuf.inrows=0;

		//这里调整merge_k,前面的mergek传入是建议值。
		if((infiles[0].max-(pa+1)*merge_k)>=0) {mergek=merge_k;}
		else mergek=infiles[0].max-pa*merge_k;

		if(mergek==1){
			free(outbuf.buf);
			fclose(newfiles[pa].f);
			remove(newfiles[pa].file);
			rename(infiles[pa*merge_k].file,newfiles[pa].file);
			continue;  
		}//只有一个文件不用合并

	    //分配段内存,读入文件
		for(k=0;k<mergek;k++){
			if((seg[k].buf=(char *)malloc(SORT_AREA_ROWS*dbfHead.record_length))==NULL){
				printf("malloc in merge sort error");
				return -1;
			}
			if((infiles[k].f=openAFile(infiles[pa*merge_k+k].file,"rb"))==NULL){
			    printf("open file %s failed",infiles[k].file);
				return -1;
			}
			//验证原文件的正确性
		    if(verifyDbfFile(infiles[k].f)==-1){
			    printf("file %s is destoryed",infiles[pa*merge_k+k].file);
			    return -1;
			}
			infiles[k].used=1;
            infiles[k].curr_read_row=0;

			fseek(infiles[k].f,0,SEEK_SET);//移动到开始位置
    		fread(&(infiles[k].dff),sizeof(DBF_FILE_HEAD),1,infiles[k].f);
#ifdef HP_UX
    		revert_unsigned_short(&(infiles[k].dff.head_length));		/* 用于定位到第一条记录*/
    		revert_unsigned_long(&(infiles[k].dff.record_num));			/* 总的记录数*/
    		revert_unsigned_short(&(infiles[k].dff.record_length));		/* 每条记录长度*/
#endif

#ifdef PRINT_MSG
    		printf("head_length:%d\n",infiles[k].dff.head_length);
    		printf("record_num:%ld\n",infiles[k].dff.record_num);
    		printf("record_length:%d\n",infiles[k].dff.record_length);
#endif

		    fseek(infiles[k].f,dbfHead.head_length,SEEK_SET);//移动到第一条记录
	

			read_data(infiles,k,seg);  //读取记录到内存段

			rec_num+=infiles[k].dff.record_num;

		}
        //写文件头。
		writeAFile(NULL,0,newfiles[pa].f,allf,2,rec_num);
		rec_num=0;

	    //k路合并
		K_Merge(infiles,newfiles,pa,seg,&outbuf,ls,exc,mergek);

		//取消内存,关闭文件或删除
    	for(k=0;k<mergek;k++){
			fclose(infiles[k].f);
			free(seg[k].buf);
			remove(infiles[pa*merge_k+k].file);
		}

		free(outbuf.buf);
		fclose(newfiles[pa].f);
#ifdef UNIX
		}          //并行系统结束
#endif
	}//for

    //递归调用本函数
	golfileId++;

    return merge_sort(newfiles,outfiles,merge_k,allf);

	return 0;
   
}

/*
功能:提取参数的值,返回1失败,返回0成功
  */
int getParaValue(char * * inpa,int start,int end){
    char tmp[30],p1[3]="-M",p2[3]="-P",* retp;
    int len=end-start+1,i=0;
	for (i=0;i<len;i++){
		if((retp=strstr(inpa[start+i],p1))!=NULL){
            strcpy(tmp,retp+2);
            max_mem=strtoul(tmp,NULL,10);
			if(max_mem<1064960 || max_mem>536870912){
				printf("max memary error it must in 1064960 and 536870912");
				exit(1);
			}
		}
#ifdef UNIX
		else if((retp=strstr(inpa[start+i],p2))!=NULL){
			strcpy(tmp,retp+2);
		    parallel_num=atoi(tmp);
			if(parallel_num>PARALLEL_MAX){
				printf("parallel number you give is too large! \n");
				exit(1);
			}
		}	
#endif
		else
			return 1;
	}
	return 0;
}

/*
 功能:验证dbf文件长度是否正确
       此函数因为有很多文件,所以需要多次
	   调用。
 参数:File	文件路径名
 返回值:0 正确,-1 错误
*/
int verifyDbfFile(FILE * afile)
{
	long fileSize = 0;
	long calSize = 0;
	DBF_FILE_HEAD dbfHead2;

	fseek(afile,0,SEEK_SET);

	fread(&dbfHead2,sizeof(DBF_FILE_HEAD),1,afile);

	fseek(afile,0,SEEK_END);
	fileSize =(long) ftell(afile);
  
	fseek(afile,0,SEEK_SET);
#ifdef HP_UX
	revert_unsigned_short(&dbfHead2.head_length);
	revert_unsigned_short(&dbfHead2.record_length);
	revert_unsigned_long(&dbfHead2.record_num);
#endif
	calSize = (long)dbfHead2.head_length + dbfHead2.record_length*dbfHead2.record_num;
	if(fileSize < calSize)
	{
#ifdef PRINT_MSG
		printf("dbfHead2.head_length:%d\n",dbfHead2.head_length);
		printf("dbfHead2.record_num:%ld\n",dbfHead2.record_num);
		printf("dbfHead2.record_length:%d\n",dbfHead2.record_length);
		printf("\tbut actual length is %ld \n",fileSize);
#endif
		return -1;
	}
	return 0;
}

/*
功能:字符和整数数值比较
      aa 要比较的字符串
	  bb 要比较的字符串
	  aalen aa字符串长度
	  bblen bb字符串长度
	  type 类型"C","N"
	  dec 是小数位数

  当aa<bb则返回-1,相等为0 否则为1
*/
int mycmp(char * aa,int aalen,char * bb,int bblen){
    char tmpaa[MAX_CMP_CHAR],tmpbb[MAX_CMP_CHAR];
	int a=0 ;
    tmpaa[aalen]='\0';
	tmpbb[bblen]='\0';

	memcpy(tmpaa,aa,aalen);
	memcpy(tmpbb,bb,bblen);
	return strcmp(tmpaa,tmpbb);
}

/*
功能:快速排序,字符型
  */
/*	
	快速排序
	传入参数:	    a:需要排序的记录集
					l:支点位置
					r:长度
					排序的字段信息在dbffield结构中
					tyy 为类型:"C"为字符
					            "N"为整数
*/
void quickSort(char *sourceArray, long first, long last)
{
	char  tmp[RECORD_MAX];
	char* list_separator;
	long low, high;
	low = first;
	high = last+1;

	//这里记录的结构是不知道的,只知道长度。
	list_separator = sourceArray+first*dbfHead.record_length;

	if(first>=last) return;
	
	while(1){
		do{
			low++;
		}while (mycmp(sourceArray+low*dbfHead.record_length+dbfField.addr, \
			         dbfField.length,list_separator+dbfField.addr,dbfField.length)<0 \
					 && low<=last );
		do{
			high--;
		}while (mycmp(sourceArray+high*dbfHead.record_length+dbfField.addr, \
			         dbfField.length,list_separator+dbfField.addr,dbfField.length)>0\
					 && first<=high );
		if(low>=high) break;

		memcpy(tmp,(char *)(sourceArray+low*dbfHead.record_length),dbfHead.record_length);
		memcpy((char *)(sourceArray+low*dbfHead.record_length),    \
			   (char *)(sourceArray+high*dbfHead.record_length),   \
			   dbfHead.record_length);
		memcpy((char *)(sourceArray+high*dbfHead.record_length),tmp,dbfHead.record_length);
	}

	    //设置pivot
	    memcpy(tmp,(char *)(sourceArray+first*dbfHead.record_length),\
			   dbfHead.record_length);
		memcpy((char *)(sourceArray+first*dbfHead.record_length),\

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -