quick_sort.c
上传用户:hhyinxing
上传日期:2013-09-10
资源大小:833k
文件大小:5k
源码类别:

并行计算

开发平台:

Unix_Linux

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <mpi.h>
  4. #define  TRUE 1
  5.  
  6. /*
  7. * 函数名: main
  8. * 功能:实现快速排序的主程序
  9. * 输入:argc为命令行参数个数;
  10. *       argv为每个命令行参数组成的字符串数组。
  11. * 输出:返回0代表程序正常结束
  12. */
  13. main(int argc,char *argv[])
  14. {
  15. int DataSize;
  16. int *data;
  17. /*MyID表示进程标志符;SumID表示组内进程数*/
  18. int MyID, SumID;
  19. int i, j;
  20. int m, r;
  21. MPI_Status status;
  22. /*启动MPI计算*/
  23. MPI_Init(&argc,&argv);
  24. /*MPI_COMM_WORLD是通信子*/
  25. /*确定自己的进程标志符MyID*/
  26. MPI_Comm_rank(MPI_COMM_WORLD,&MyID);
  27. /*组内进程数是SumID*/
  28. MPI_Comm_size(MPI_COMM_WORLD,&SumID);
  29. /*根处理机(MyID=0)获取必要信息,并分配各处理机进行工作*/
  30. if(MyID==0)
  31. {
  32. /*获取待排序数组的长度*/
  33. DataSize=GetDataSize();
  34. data=(int *)malloc(DataSize*sizeof(int));
  35. /*内存分配错误*/
  36. if(data==0) 
  37. ErrMsg("Malloc memory error!");
  38. /*动态生成待排序序列*/
  39. srand(396);
  40. for(i=0;i<DataSize;i++)
  41. {
  42. data[i]=(int)rand();
  43. printf("%10d",data[i]);
  44. }
  45. printf("n");
  46. }
  47. m=log2(SumID);
  48. /* 从根处理器将数据序列广播到其他处理器*/
  49. /*{"1"表示传送的输入缓冲中的元素的个数,    */
  50. /* "MPI_INT"表示输入元素的类型,    */ 
  51. /* "0"表示root processor的ID  }    */
  52. MPI_Bcast(&DataSize,1,MPI_INT,0,MPI_COMM_WORLD);
  53. /*ID号为0的处理器调度执行排序*/
  54. para_QuickSort(data,0,DataSize-1,m,0,MyID);
  55.     
  56. /*ID号为0的处理器打印排序完的有序序列*/
  57. if(MyID==0)
  58. {
  59. for(i=0;i<DataSize;i++)
  60. {
  61. printf("%10d",data[i]);
  62. }
  63. printf("n");
  64. }
  65. MPI_Finalize(); //结束计算
  66. }
  67. /*
  68. * 函数名: para_QuickSort
  69. * 功能:并行快速排序,对起止位置为start和end的序列,使用2的m次幂个处理器进行排序
  70. * 输入:无序数组data[1,n],使用的处理器个数2^m
  71. * 输出:有序数组data[1,n]
  72. */
  73. para_QuickSort(int *data,int start,int end,int m,int id,int MyID)
  74. {
  75. int i, j;
  76. int r;
  77. int MyLength;
  78. int *tmp;
  79. MPI_Status status;
  80. MyLength=-1;
  81. /*如果可供选择的处理器只有一个,那么由处理器id调用串行排序,对应于算法13.4步骤(1.1)*/
  82. /*(1.1) Pid call quicksort(data,i,j) */
  83. if(m==0)
  84. {
  85. if(MyID==id)
  86. QuickSort(data,start,end);
  87. return;
  88. }
  89. /*由第id号处理器划分数据,并将后一部分数据发送到处理器id+exp2(m-1),对应于算法13.4步骤(1.2,1.3)*/
  90. /*(1.2) Pid: r=patrition(data,i,j)*/
  91. if(MyID==id)
  92. {
  93. /*将当前的无序区R[1,n]划分成左右两个无序的子区R[1,i-1]和R[i,n](1≤i≤n)*/
  94. r=Partition(data,start,end);
  95. MyLength=end-r;
  96. /*(1.3) Pid send data[r+1,m-1] to P(id+2m-1) */
  97. /* {MyLength表示发送缓冲区地址;*/
  98. /*  发送元素数目为1;    */
  99. /*  MyID是消息标签 }    */
  100. MPI_Send(&MyLength,1,MPI_INT,id+exp2(m-1),MyID,MPI_COMM_WORLD);
  101. /*若缓冲区不空,则第id+2m-1号处理器取数据的首址是data[r+1]*/
  102. if(MyLength!=0)
  103. MPI_Send(data+r+1,MyLength,MPI_INT,id+exp2(m-1),MyID,MPI_COMM_WORLD);
  104. }
  105. /*处理器id+exp2(m-1)接受处理器id发送的消息*/
  106. if(MyID==id+exp2(m-1))
  107. {
  108. MPI_Recv(&MyLength,1,MPI_INT,id,id,MPI_COMM_WORLD,&status);
  109. if(MyLength!=0)
  110. {
  111. tmp=(int *)malloc(MyLength*sizeof(int));
  112. if(tmp==0) ErrMsg("Malloc memory error!");
  113. MPI_Recv(tmp,MyLength,MPI_INT,id,id,MPI_COMM_WORLD,&status);
  114. }
  115. }
  116. /*递归调用并行排序,对应于算法13.4步骤(1.4,1.5)*/
  117. /*用2^m-1个处理器对start--(r-1)的数据进行递归排序*/
  118. j=r-1-start;
  119. MPI_Bcast(&j,1,MPI_INT,id,MPI_COMM_WORLD);
  120. /*(1.4) para_quicksort(data,i,r-1,m-1,id)*/
  121. if(j>0)
  122. para_QuickSort(data,start,r-1,m-1,id,MyID);
  123. /*用2^m-1个处理器对(r+1)--end的数据进行递归排序*/
  124. j=MyLength;
  125. MPI_Bcast(&j,1,MPI_INT,id,MPI_COMM_WORLD);
  126. /*(1.5) para_quicksort(data,r+1,j,m-1,id+2m-1)*/
  127. if(j>0)
  128. para_QuickSort(tmp,0,MyLength-1,m-1,id+exp2(m-1),MyID);
  129. /*将排序好的数据由处理器id+exp2(m-1)发回id号处理器,对应于算法13.4步骤(1.6)*/
  130. /*(1.6) P(id+2m-1) send data[r+1,m-1] back to Pid */
  131. if((MyID==id+exp2(m-1)) && (MyLength!=0))
  132. MPI_Send(tmp,MyLength,MPI_INT,id,id+exp2(m-1),MPI_COMM_WORLD);
  133. if((MyID==id) && (MyLength!=0))
  134. MPI_Recv(data+r+1,MyLength,MPI_INT,id+exp2(m-1),id+exp2(m-1),MPI_COMM_WORLD,&status);
  135. }
  136. /*
  137. * 函数名: QuickSort
  138. * 功能:对起止位置为start和end的数组序列,进行串行快速排序。
  139. * 输入:无序数组data[1,n]
  140. * 返回:有序数组data[1,n]
  141. */
  142. QuickSort(int *data,int start,int end)
  143. {
  144. int r;
  145. int i;
  146. if(start<end)
  147. {
  148. r=Partition(data,start,end);
  149. QuickSort(data,start,r-1);
  150. QuickSort(data,r+1,end);
  151. }
  152. }
  153. /*
  154. * 函数名: Partition
  155. * 功能:对起止位置为start和end的数组序列,将其分成两个非空子序列,
  156. * 其中前一个子序列中的任意元素小于后个子序列的元素。
  157. * 输入:无序数组data[1,n]
  158. * 返回: 两个非空子序列的分界下标
  159. */
  160. int Partition(int *data,int start,int end)
  161. {
  162. int pivo;
  163. int i, j;
  164. int tmp;
  165. pivo=data[end];
  166. i=start-1; /*i(活动指针)*/
  167. for(j=start;j<end;j++)
  168. if(data[j]<=pivo)
  169. {
  170. i++; /*i表示比pivo小的元素的个数*/
  171. tmp=data[i];
  172. data[i]=data[j];
  173. data[j]=tmp;
  174. }
  175. tmp=data[i+1];
  176. data[i+1]=data[end];
  177. data[end]=tmp; /*以pivo为分界,data[i+1]=pivo*/
  178. return i+1;
  179. }
  180. /*
  181. * 函数名: exp2
  182. * 功能:求2的num次幂
  183. * 输入:int型数据num
  184. * 返回: 2的num次幂
  185. */
  186. int exp2(int num)
  187. {
  188. int i;
  189. i=1;
  190. while(num>0)
  191. {
  192. num--;
  193. i=i*2;
  194. }
  195. return i;
  196. }
  197. /*
  198. * 函数名: log2
  199. * 功能:求以2为底的num的对数
  200. * 输入:int型数据num
  201. * 返回: 以2为底的num的对数
  202. */
  203. int log2(int num)
  204. {
  205. int i, j;
  206. i=1;
  207. j=2;
  208. while(j<num)
  209. {
  210. j=j*2;
  211. i++;
  212. }
  213. if(j>num)
  214. i--;
  215. return i;
  216. }
  217. /*
  218. * 函数名: GetDataSize
  219. * 功能:读入待排序序列长度
  220. */
  221. int GetDataSize()
  222. {
  223. int i;
  224. while(TRUE)
  225. {
  226. printf("Input the Data Size :");
  227. scanf("%d",&i);
  228. /*读出正确的i,返回;否则,继续要求输入*/
  229. if((i>0) && (i<=65535))
  230. break;
  231. ErrMsg("Wrong Data Size, must between [1..65535]");
  232. }
  233. return i;
  234. }
  235. /*输出错误信息*/
  236. ErrMsg(char *msg)
  237. {
  238. printf("Error: %s n",msg);
  239. }