📄 quick_sort.c
字号:
#include <stdio.h>#include <stdlib.h>#include <mpi.h>#define TRUE 1 /* * 函数名: main * 功能:实现快速排序的主程序 * 输入:argc为命令行参数个数; * argv为每个命令行参数组成的字符串数组。 * 输出:返回0代表程序正常结束*/main(int argc,char *argv[]){ int DataSize; int *data; /*MyID表示进程标志符;SumID表示组内进程数*/ int MyID, SumID; int i, j; int m, r; MPI_Status status; /*启动MPI计算*/ MPI_Init(&argc,&argv); /*MPI_COMM_WORLD是通信子*/ /*确定自己的进程标志符MyID*/ MPI_Comm_rank(MPI_COMM_WORLD,&MyID); /*组内进程数是SumID*/ MPI_Comm_size(MPI_COMM_WORLD,&SumID); /*根处理机(MyID=0)获取必要信息,并分配各处理机进行工作*/ if(MyID==0) { /*获取待排序数组的长度*/ DataSize=GetDataSize(); data=(int *)malloc(DataSize*sizeof(int)); /*内存分配错误*/ if(data==0) ErrMsg("Malloc memory error!"); /*动态生成待排序序列*/ srand(396); for(i=0;i<DataSize;i++) { data[i]=(int)rand(); printf("%10d",data[i]); } printf("\n"); } m=log2(SumID); /* 从根处理器将数据序列广播到其他处理器*/ /*{"1"表示传送的输入缓冲中的元素的个数, */ /* "MPI_INT"表示输入元素的类型, */ /* "0"表示root processor的ID } */ MPI_Bcast(&DataSize,1,MPI_INT,0,MPI_COMM_WORLD); /*ID号为0的处理器调度执行排序*/ para_QuickSort(data,0,DataSize-1,m,0,MyID); /*ID号为0的处理器打印排序完的有序序列*/ if(MyID==0) { for(i=0;i<DataSize;i++) { printf("%10d",data[i]); } printf("\n"); } MPI_Finalize(); //结束计算}/* * 函数名: para_QuickSort * 功能:并行快速排序,对起止位置为start和end的序列,使用2的m次幂个处理器进行排序 * 输入:无序数组data[1,n],使用的处理器个数2^m * 输出:有序数组data[1,n]*/para_QuickSort(int *data,int start,int end,int m,int id,int MyID){ int i, j; int r; int MyLength; int *tmp; MPI_Status status; MyLength=-1; /*如果可供选择的处理器只有一个,那么由处理器id调用串行排序,对应于算法13.4步骤(1.1)*/ /*(1.1) Pid call quicksort(data,i,j) */ if(m==0) { if(MyID==id) QuickSort(data,start,end); return; } /*由第id号处理器划分数据,并将后一部分数据发送到处理器id+exp2(m-1),对应于算法13.4步骤(1.2,1.3)*/ /*(1.2) Pid: r=patrition(data,i,j)*/ if(MyID==id) { /*将当前的无序区R[1,n]划分成左右两个无序的子区R[1,i-1]和R[i,n](1≤i≤n)*/ r=Partition(data,start,end); MyLength=end-r; /*(1.3) Pid send data[r+1,m-1] to P(id+2m-1) */ /* {MyLength表示发送缓冲区地址;*/ /* 发送元素数目为1; */ /* MyID是消息标签 } */ MPI_Send(&MyLength,1,MPI_INT,id+exp2(m-1),MyID,MPI_COMM_WORLD); /*若缓冲区不空,则第id+2m-1号处理器取数据的首址是data[r+1]*/ if(MyLength!=0) MPI_Send(data+r+1,MyLength,MPI_INT,id+exp2(m-1),MyID,MPI_COMM_WORLD); } /*处理器id+exp2(m-1)接受处理器id发送的消息*/ if(MyID==id+exp2(m-1)) { MPI_Recv(&MyLength,1,MPI_INT,id,id,MPI_COMM_WORLD,&status); if(MyLength!=0) { tmp=(int *)malloc(MyLength*sizeof(int)); if(tmp==0) ErrMsg("Malloc memory error!"); MPI_Recv(tmp,MyLength,MPI_INT,id,id,MPI_COMM_WORLD,&status); } } /*递归调用并行排序,对应于算法13.4步骤(1.4,1.5)*/ /*用2^m-1个处理器对start--(r-1)的数据进行递归排序*/ j=r-1-start; MPI_Bcast(&j,1,MPI_INT,id,MPI_COMM_WORLD); /*(1.4) para_quicksort(data,i,r-1,m-1,id)*/ if(j>0) para_QuickSort(data,start,r-1,m-1,id,MyID); /*用2^m-1个处理器对(r+1)--end的数据进行递归排序*/ j=MyLength; MPI_Bcast(&j,1,MPI_INT,id,MPI_COMM_WORLD); /*(1.5) para_quicksort(data,r+1,j,m-1,id+2m-1)*/ if(j>0) para_QuickSort(tmp,0,MyLength-1,m-1,id+exp2(m-1),MyID); /*将排序好的数据由处理器id+exp2(m-1)发回id号处理器,对应于算法13.4步骤(1.6)*/ /*(1.6) P(id+2m-1) send data[r+1,m-1] back to Pid */ if((MyID==id+exp2(m-1)) && (MyLength!=0)) MPI_Send(tmp,MyLength,MPI_INT,id,id+exp2(m-1),MPI_COMM_WORLD); if((MyID==id) && (MyLength!=0)) MPI_Recv(data+r+1,MyLength,MPI_INT,id+exp2(m-1),id+exp2(m-1),MPI_COMM_WORLD,&status);}/* * 函数名: QuickSort * 功能:对起止位置为start和end的数组序列,进行串行快速排序。 * 输入:无序数组data[1,n] * 返回:有序数组data[1,n]*/QuickSort(int *data,int start,int end){ int r; int i; if(start<end) { r=Partition(data,start,end); QuickSort(data,start,r-1); QuickSort(data,r+1,end); }}/* * 函数名: Partition * 功能:对起止位置为start和end的数组序列,将其分成两个非空子序列, * 其中前一个子序列中的任意元素小于后个子序列的元素。 * 输入:无序数组data[1,n] * 返回: 两个非空子序列的分界下标*/int Partition(int *data,int start,int end){ int pivo; int i, j; int tmp; pivo=data[end]; i=start-1; /*i(活动指针)*/ for(j=start;j<end;j++) if(data[j]<=pivo) { i++; /*i表示比pivo小的元素的个数*/ tmp=data[i]; data[i]=data[j]; data[j]=tmp; } tmp=data[i+1]; data[i+1]=data[end]; data[end]=tmp; /*以pivo为分界,data[i+1]=pivo*/ return i+1;}/* * 函数名: exp2 * 功能:求2的num次幂 * 输入:int型数据num * 返回: 2的num次幂*/int exp2(int num){ int i; i=1; while(num>0) { num--; i=i*2; } return i;}/* * 函数名: log2 * 功能:求以2为底的num的对数 * 输入:int型数据num * 返回: 以2为底的num的对数*/int log2(int num){ int i, j; i=1; j=2; while(j<num) { j=j*2; i++; } if(j>num) i--; return i;}/* * 函数名: GetDataSize * 功能:读入待排序序列长度*/int GetDataSize(){ int i; while(TRUE) { printf("Input the Data Size :"); scanf("%d",&i); /*读出正确的i,返回;否则,继续要求输入*/ if((i>0) && (i<=65535)) break; ErrMsg("Wrong Data Size, must between [1..65535]"); } return i;}/*输出错误信息*/ErrMsg(char *msg){ printf("Error: %s \n",msg);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -