<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_jiahaipeng</title><subtitle type="text">我要飞得更高</subtitle><id>http://feed.cnblogs.com/blog/u/31490/rss</id><updated>2010-04-19T02:45:15Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/31490/rss"/><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2010/04/19/1715115.html</id><title type="text">MPI并行编程系列之五：图的单源最短路径算法</title><summary type="text">图的单源最短路径问题是指求一个从指定的顶点s到其他所有顶点i之间的最短距离。因为是从一点到其他顶点的距离，所以称谓单源。本文将介绍dijkstra算法：按路径长度递增次序的最短路径算法，并给出了对该算法MPI并行化算法。 一、算法思想 该算法的思想是：引入一个辅助向量D，它的每个分量D[i]为源顶点v到其他顶点v[i]的路径长度。初始态为：如有从v到vi的路径，则D[i]为弧[v,vi]的权值；否...</summary><published>2010-04-19T01:15:00Z</published><updated>2010-04-19T01:15:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/19/1715115.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/19/1715115.html"/><content type="html">&lt;p&gt;图的单源最短路径问题是指求一个从指定的顶点s到其他所有顶点i之间的最短距离。因为是从一点到其他顶点的距离，所以称谓单源。本文将介绍dijkstra算法：按路径长度递增次序的最短路径算法，并给出了对该算法MPI并行化算法。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;一、算法思想&amp;nbsp; &lt;/strong&gt;&lt;/p&gt; &lt;p&gt;该算法的思想是：引入一个辅助向量D，它的每个分量D[i]为源顶点v到其他顶点v[i]的路径长度。初始态为：如有从v到vi的路径，则D[i]为弧[v,vi]的权值；否则D[i]为无穷大。显然&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;D[j] = min{D[i]}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;为顶点v出发到其他顶点的一条最短路径的长度，其路径为（v，vj）。&lt;/p&gt; &lt;p&gt;那么下一条最短路径长度如何计算呢？其实很简单，下一条最短路径长度要么是源顶点v直接到某一顶点vk的长度，即{v，vk}。要么是源顶点v经过顶点vj到某一顶点的长度，即{v，vj，vk}。&lt;/p&gt; &lt;p&gt;我们假设S为已经求得最短路径的顶点的集合，那么下一条最短路径（设其终点为x），要么是弧{v， vx}，要么为中间只经过S中顶点而最后到达终点X的路径。&lt;/p&gt; &lt;p&gt;在一般情况下，下一条最短路径的长度为：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;D[j] = min{D[i] | vi 属于 V-S}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;其中V为图顶点的集合， D[i]为弧{v， vi}的权值，或者为D[k]和弧{vk， vi}权值之和。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;二、算法描述&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;根据以上思想，我们得到算法描述如下：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;输入：图G的邻接矩阵m[0...n-1][0...n-1]，源顶点 v&lt;/p&gt; &lt;p&gt;输出：最短路径值向量D[0...n-1], 最短路径矩阵p[0...n-1][0...n-2].其中D[i]为源顶点v到顶点vi的最短路径长度，向量p[i]为源顶点v到顶点vi的最短路径&lt;/p&gt; &lt;p&gt;1）初始化D[i]&lt;/p&gt; &lt;p&gt;D[i] = m[v][vi] == 无穷大 ? 无穷大 : m[v][vi]&lt;/p&gt; &lt;p&gt;2)计算当前最短路径值&lt;/p&gt; &lt;p&gt;min = min{D[i]}&lt;/p&gt; &lt;p&gt;final[i] = 1&amp;nbsp;&amp;nbsp; //标记顶点i已经取得最短路径&lt;/p&gt; &lt;p&gt;3）更新最短路径值及最短路径&lt;/p&gt; &lt;p&gt;for(i = 0; i &amp;lt; n; i++)&lt;/p&gt; &lt;p&gt;if(!final[i])&lt;/p&gt; &lt;p&gt;if(D[i] &amp;gt; min + m[vk][vi])&lt;/p&gt; &lt;p&gt;D[i] = min + m[vk][vi];&lt;/p&gt; &lt;p&gt;end if&lt;/p&gt; &lt;p&gt;endif&lt;/p&gt; &lt;p&gt;for( j = 0; j &amp;lt; n-1 ; j++)&lt;/p&gt; &lt;p&gt;if(p[vk][j] != 无穷大)&lt;/p&gt; &lt;p&gt;p[vi][j] = p[vk][j];&lt;/p&gt; &lt;p&gt;end if&lt;/p&gt; &lt;p&gt;end for&lt;/p&gt; &lt;p&gt;p[vi][j] = vi&lt;/p&gt; &lt;p&gt;end for&lt;/p&gt; &lt;p&gt;4) 输出最短路径和最短路径值&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;strong&gt;三、算法实现&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;这里只给出算法的核心代码， 如下：&lt;/p&gt; &lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt; short_path_function(&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; **matrix,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; vertex_num,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; vertex_source){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *short_path_value;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *final;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *short_path_storage;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; **short_path;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; min;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; vertex;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; i,j,k;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;    &lt;span &gt;//分配空间&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;    short_path_value = my_malloc(&lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * vertex_num);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;    final = my_malloc(&lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * vertex_num);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;    dynamic_allocate_matrix((&lt;span &gt;void&lt;/span&gt; *)&amp;amp;short_path, (&lt;span &gt;void&lt;/span&gt; *)&amp;amp;short_path_storage, vertex_num,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;            vertex_num-1, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;));&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  23:  &lt;/span&gt;    &lt;span &gt;//初始化&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;    &lt;span &gt;for&lt;/span&gt;(i = 0; i &amp;lt; vertex_num; i++){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  25:  &lt;/span&gt;        final[i] = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;        short_path_value[i] = matrix[vertex_source][i];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  27:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;        &lt;span &gt;//设置空路径&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  29:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt;(j = 0; j &amp;lt; vertex_num-1; j++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;            short_path[i][j] = -1;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  31:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;        &lt;span &gt;//初始化路径&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  33:  &lt;/span&gt;        &lt;span &gt;if&lt;/span&gt;(short_path_value[i] &amp;lt; MAX_VAULE)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;            short_path[i][0] = i;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  35:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  37:  &lt;/span&gt;    final[vertex_source] = 1;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  38:  &lt;/span&gt;    &lt;span &gt;for&lt;/span&gt;(i = 1; i &amp;lt; vertex_num; i++){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  39:  &lt;/span&gt;        &lt;span &gt;//找出从源顶点出发的一条最短路径长度顶点&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  40:  &lt;/span&gt;        min =MAX_VAULE ;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  41:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt;(j = 0; j &amp;lt; vertex_num; j++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  42:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt;(!final[j])&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  43:  &lt;/span&gt;                &lt;span &gt;if&lt;/span&gt;(short_path_value[j] &amp;lt; min){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  44:  &lt;/span&gt;                    min = short_path_value[j];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  45:  &lt;/span&gt;                    vertex = j;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  46:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  47:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  48:  &lt;/span&gt;        final[vertex] = 1;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  49:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  50:  &lt;/span&gt;        &lt;span &gt;//跟新最短路径&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  51:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt;(j = 0; j &amp;lt; vertex_num; j++){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  52:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt;(!final[j])&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  53:  &lt;/span&gt;                &lt;span &gt;if&lt;/span&gt;(min + matrix[vertex][j] &amp;lt; short_path_value[j]){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  54:  &lt;/span&gt;                    &lt;span &gt;//跟新最短路径长度&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  55:  &lt;/span&gt;                    short_path_value[j] = min + matrix[vertex][j];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  56:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  57:  &lt;/span&gt;                    &lt;span &gt;//更新路径&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  58:  &lt;/span&gt;                    k = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  59:  &lt;/span&gt;                    &lt;span &gt;while&lt;/span&gt;(short_path[vertex][k] != -1){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  60:  &lt;/span&gt;                        short_path[j][k] = short_path[vertex][k];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  61:  &lt;/span&gt;                        k++;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  62:  &lt;/span&gt;                    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  63:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  64:  &lt;/span&gt;                    short_path[j][k] = j;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  65:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  66:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  67:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  68:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  69:  &lt;/span&gt;    &lt;span &gt;//打印结果&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  70:  &lt;/span&gt;    array_int_print(vertex_num, short_path_value);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  71:  &lt;/span&gt;    print_int_matrix(short_path, vertex_num-1, vertex_num);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  72:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;strong&gt;四、并行算法描述&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;我们对这个算法进行并行化分析，显然初始化向量D（对应于算法的第一步），更新最短路径值和最短路径（对应于算法的第三步）是可以并行化实现的，因为只要有了当前最短路径和最短路径值，各个顶点的最短路径的算法是相互独立的。在本并行化算法中，如何求得当前的最短路径和最短路径值成为关键。&lt;/p&gt;&#xD;
&lt;p&gt;我们假设一共用P个进程，图右n个顶点，我们让每个进程负责n/p个顶点，每个进程都有自己的向量D和最短路径p，我们如何求得当前的最短路径长度和最短路径呢？首先，我们可以计算出各个进程的当前最短路径，并将局部最短路径发往进程0，进程0对这些进程的最短路径进行比较，取得当前的全局最短路径，并将这一结果广播到所有的进程。&lt;/p&gt;&#xD;
&lt;p&gt;其算法描述如下：&lt;/p&gt;&#xD;
&lt;p&gt;我们假设总共有p个进程&lt;/p&gt;&#xD;
&lt;p&gt;输入：图G的邻接矩阵m[0...n-1][0...n-1]，源顶点 v&lt;/p&gt;&#xD;
&lt;p&gt;输出：最短路径值向量D[0...n-1], 最短路径矩阵p[0...n-1][0...n-2].&lt;/p&gt;&#xD;
&lt;p&gt;&lt;font size="2" face="Consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1） 进程0读取邻接矩阵m和源节点v，并将m，v广播到其他所有的进程&lt;/font&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;font size="2" face="Consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2） 各进程并行初始化各自的局部D和P&lt;/font&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;font size="2" face="Consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）求最短路径&lt;/font&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;font size="2" face="Consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）各进程并行计算出各自的局部最短路径值，并将其发送0号进程&lt;/font&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;font size="2" face="Consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）0号进程求出全局最短路径值和对应的进程号，并将其广播到其他所有的进程。&lt;/font&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;font size="2" face="Consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）拥有全局最短路径值的进程将其对应的最短路径广播到其他进程（用于更新各个进程的最短路径）&lt;/font&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;font size="2" face="Consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4）各进程并行跟新各自的D和P&lt;/font&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;五、 并行算法实现&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;我们这里只给出算法中第三步的具体实现：&lt;/p&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;int&lt;/span&gt; get_short_path_value(&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; *final,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; *vertex,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; **short_path,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; *short_path_value,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; *short_path_copy,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; *shortest,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; vertex_num,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; local_vertex_num,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; process_id,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; process_size,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;        MPI_Comm comm){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; min;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; local_vertex;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; shortest_process_id;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;    MPI_Status status;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; j;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;    &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  23:  &lt;/span&gt;    &lt;span &gt;//取到每个进程的路径的最小值&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;    min = MAX_VAULE;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  25:  &lt;/span&gt;    &lt;span &gt;for&lt;/span&gt;(j = 0; j &amp;lt; local_vertex_num; j++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;        &lt;span &gt;if&lt;/span&gt;(!final[j])&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  27:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt;(short_path_value[j] &amp;lt; min){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;                min = short_path_value[j];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  29:  &lt;/span&gt;                local_vertex = j;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  31:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;    &lt;span &gt;//各进程将自己的最小路径值发往0号进程&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  33:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_id)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;         MPI_Send(&amp;amp;min, 1, MPI_INT, 0, DATA_MESSAGE, comm); &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  35:  &lt;/span&gt;    &lt;span &gt;else&lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;        &lt;span &gt;//0号进程收集所有进程的最小值&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  37:  &lt;/span&gt;        shortest[0] = min;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  38:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt;(j = 1; j &amp;lt; process_size; j++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  39:  &lt;/span&gt;            MPI_Recv(shortest+j, 1, MPI_INT, j, DATA_MESSAGE, comm, &amp;amp;status);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  40:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  41:  &lt;/span&gt;         &lt;span &gt;//0号进程计算出全局最小值，并广播到其他各个进程&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  42:  &lt;/span&gt;          min = shortest[0];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  43:  &lt;/span&gt;          shortest_process_id = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  44:  &lt;/span&gt;          &lt;span &gt;for&lt;/span&gt;(j = 1; j &amp;lt; process_size; j++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  45:  &lt;/span&gt;             &lt;span &gt;if&lt;/span&gt;(shortest[j] &amp;lt; min){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  46:  &lt;/span&gt;                 min = shortest[j];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  47:  &lt;/span&gt;                 shortest_process_id = j;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  48:  &lt;/span&gt;              }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  49:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  50:  &lt;/span&gt;    &lt;span &gt;//0号进程将最小值广播到所有进程,如果最小值为无穷大，则返回&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  51:  &lt;/span&gt;    MPI_Bcast(&amp;amp;min, 1, MPI_INT, 0, comm);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  52:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(min == MAX_VAULE)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  53:  &lt;/span&gt;        &lt;span &gt;return&lt;/span&gt; min;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  54:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  55:  &lt;/span&gt;    &lt;span &gt;//0号进程将最小值所属的进程广播到所有的进程&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  56:  &lt;/span&gt;    MPI_Bcast(&amp;amp;shortest_process_id, 1, MPI_INT, 0, comm);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  57:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  58:  &lt;/span&gt;    &lt;span &gt;//拥有最小值的进程，将其对应的标志位标1，并计算该坐标的全局坐标&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  59:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_id == shortest_process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  60:  &lt;/span&gt;        final[local_vertex] = 1;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  61:  &lt;/span&gt;        *vertex = BLOCK_LOW(shortest_process_id, process_size, vertex_num) + local_vertex;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  62:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  63:  &lt;/span&gt;        &lt;span &gt;//复制最短路径&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  64:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt;(j = 0; j &amp;lt; vertex_num -1; j++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  65:  &lt;/span&gt;            short_path_copy[j] = short_path[local_vertex][j];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  66:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  67:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  68:  &lt;/span&gt;    &lt;span &gt;//广播最短路径&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  69:  &lt;/span&gt;    MPI_Bcast(short_path_copy, vertex_num-1, MPI_INT, shortest_process_id,comm);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  70:  &lt;/span&gt;    MPI_Bcast(vertex, 1, MPI_INT, shortest_process_id, comm);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  71:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  72:  &lt;/span&gt;    &lt;span &gt;return&lt;/span&gt; min;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  73:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;strong&gt;六、MPI函数说明&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;本并行算法用到的MPI函数主要为点对点通信函数MPI_Send和MPI_Recv，全局通信函数MPI_Bcast。MPI名字起的真好，消息传递编程，我觉得ＭＰＩ算法的核心就是任务的划分和任务间的通信。&lt;/p&gt;&#xD;
&lt;p&gt;下篇将介绍图的最下生成树及其并行算法。&lt;/p&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&lt;/div&gt;&lt;img src="http://www.cnblogs.com/jiahaipeng/aggbug/1715115.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/19/1715115.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2010/04/15/1712335.html</id><title type="text">MPI并行编程系列之四：KMP算法及并行化</title><summary type="text">串匹配问题是计算机科学中的一个基本问题，在文字编辑、图像处理等利于都得到了广泛的应用，串匹配算法在这些应用中起到至关重要的作用。因此研究快速的串匹配算法具有重要的理论和实际意义。  KMP是一种改进的字符串模式匹配的算法，他能够在o(m+n)时间复杂度内完成字符串的模式匹配算法。本文将详细的介绍KMP算法的思想，串行及并行实现。 一、KMP算法思想  1、问题描述  给定主串S[0...n-1]、...</summary><published>2010-04-15T01:31:00Z</published><updated>2010-04-15T01:31:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/15/1712335.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/15/1712335.html"/><content type="html">&lt;p&gt;串匹配问题是计算机科学中的一个基本问题，在文字编辑、图像处理等利于都得到了广泛的应用，串匹配算法在这些应用中起到至关重要的作用。因此研究快速的串匹配算法具有重要的理论和实际意义。&lt;/p&gt; &lt;p&gt;KMP是一种改进的字符串模式匹配的算法，他能够在o(m+n)时间复杂度内完成字符串的模式匹配算法。本文将详细的介绍KMP算法的思想，串行及并行实现。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;一、KMP算法思想&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;1、问题描述&lt;/p&gt; &lt;p&gt;给定主串S[0...n-1]、模式串T[0...m-1]，其中m&amp;lt;=n。在主串S中找出所有模式串T的起始位置。&lt;/p&gt; &lt;p&gt;2、算法思想&lt;/p&gt; &lt;p&gt;令指针i指向主串S，指针j指向模式串T中当前正在比较的位置。令指针i和指针j指向的字符比较之，如两字符相等，则顺次比较后面的字符；如不相等，则指针i不动，回溯指针j，令其指向模式串T的第pos个字符，使T[0...pos-1] == S[i-pos, i-1],然后，指针i和指针j所指向的字符按此种方法继续比较，知道j == m-1，即在主串S中找到模式串T为止。&lt;/p&gt; &lt;p&gt;从算法的思想思想中我们可以看出，其算法的难点在于如何求出指针j的回溯值，即：当指针j回溯时，j将指向的位置，我们几位next[j]。下面我们首先对kmp的算法做出详细的描述。&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;strong&gt;二、KMP算法描述&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;输入：主串S[0...n-1], 模式串T[0...m-1]&lt;/p&gt; &lt;p&gt;输出：m[0...n-1],当m[i] = 1时，则主串S中匹配到模式串，且i为起始位置&lt;/p&gt; &lt;p&gt;begin&lt;/p&gt; &lt;p&gt;i = 0； j = 0;&lt;/p&gt; &lt;p&gt;while(i &amp;lt; n)&lt;/p&gt; &lt;p&gt;if(S[i] != T[j])&lt;/p&gt; &lt;p&gt;j = next[j]&lt;/p&gt; &lt;p&gt;if( j == -1)&lt;/p&gt; &lt;p&gt;i++&amp;nbsp;&amp;nbsp; j++&lt;/p&gt; &lt;p&gt;endif;&lt;/p&gt; &lt;p&gt;contiue;&lt;/p&gt; &lt;p&gt;endif&lt;/p&gt; &lt;p&gt;if (j == m-1)&lt;/p&gt; &lt;p&gt;m[i-j+1] = 1&lt;/p&gt; &lt;p&gt;j = -1 &lt;/p&gt; &lt;p&gt;i = i-j+1&lt;/p&gt; &lt;p&gt;endif&lt;/p&gt; &lt;p&gt;i++&amp;nbsp;&amp;nbsp;&amp;nbsp; j++&lt;/p&gt; &lt;p&gt;end while&lt;/p&gt; &lt;p&gt;end&lt;/p&gt; &lt;p&gt;在上面的算法描述中，next函数的编写为整个算法的核心，设计出快速正确的next函数也为KMP算法的重中之重。如何设计我们的next函数呢，我们利用递推思想：&lt;/p&gt; &lt;p&gt;1）令next[0] = -1，（为什么要等于-1呢，从上面的算法可以看出，当next[j] == -1时，证明字符串匹配要从模式串的第0个字符开始,且第0个字符并不和主串的第i个字符相等，i指针向前移动。）&lt;/p&gt; &lt;p&gt;2）假设next[j] = k ,说明T[0..k-1] == T[j-k...j-1]&lt;/p&gt; &lt;p&gt;3)&amp;nbsp; 现在我们来求next[j+1]&lt;/p&gt; &lt;p&gt;3.1 当T[j] == T[k]时,说明T[0..k] == T[j-k..j],这时分为两种情况讨论：&lt;/p&gt; &lt;p&gt;3.1.1 当T[j+1] != T[k+1]，显然&lt;/p&gt; &lt;p&gt;next[j+1] = k+1;&lt;/p&gt; &lt;p&gt;3.1.2 当T[j+1] == T[k+1]，当这两个字符相等时，说明T[k+1]和T[j+1]一样，都不和主串的字符相匹配，因此：&lt;/p&gt; &lt;p&gt;m = k+1, j=next[m] 直到T[m] != t[j+1]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;p&gt;next[j+1] = m&lt;/p&gt; &lt;p&gt;3.2&amp;nbsp; 当T[j] != T[k]时,我们必须在T[0..k-1]中找到next[j+1],这时：&lt;/p&gt; &lt;p&gt;k = next[k],直到T[j] ==T[k]&amp;nbsp; &lt;/p&gt; &lt;p&gt;next[j+1] = next[k]&lt;/p&gt; &lt;p&gt;这样我们就通过数学中递推的方式求得了匹配串T的next函数。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;三、串行实现&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;有了以上的算法描述，我们可以编写我们的kmp串行实现，本文不想黏贴过多的代码，仅仅给出next函数的实现：&lt;/p&gt; &lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;int&lt;/span&gt; *get_next(&lt;span &gt;char&lt;/span&gt; *match_string, &lt;span &gt;int&lt;/span&gt; match_string_length){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *next;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; next_index;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; i;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;    next = (&lt;span &gt;int&lt;/span&gt; *)my_malloc(&lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * match_string_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    next[0] = -1;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;    i =0;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    next_index = -1 ;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;    &lt;span &gt;while&lt;/span&gt;(i &amp;lt; match_string_length){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;        &lt;span &gt;if&lt;/span&gt;(next_index == -1 || match_string[next_index] == match_string[i]){&lt;span &gt;//对应于3.1&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;            i++; &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;            next_index++;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt;(match_string[i] != match_string[next_index])&lt;span &gt;//对应于3.1.1&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;                next[i] = next_index;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;            &lt;span &gt;else&lt;/span&gt;&lt;span &gt;//对应于3.1.2&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  23:  &lt;/span&gt;                next[i] = next[next_index];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  25:  &lt;/span&gt;        &lt;span &gt;else&lt;/span&gt;&lt;span &gt;//对应于3.2&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;            next_index = next[next_index];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  27:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  29:  &lt;/span&gt;    &lt;span &gt;return&lt;/span&gt; next;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;四：并行算法&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;现在我们考虑如何将KMP算法并行化，我们很容易考虑到得是将主串S平均分成P段（假设有p个处理器），每个处理器处理其中的一段。但这时要考虑一个问题，那就是如何处理每段字符串最后m-1个子字符串的匹配问题，因为这m-1个字符可能会和其后一段的前t个字符共同构成模式串。我们首先考虑到得是每个处理器将其负责字符串的后m-1个字符的字串发送给其后面的处理器，但这样会造成通信过大的问题，每个处理器都要发送m-1个字符。如何减少处理器间的通信呢？起始我们只需发送和模式串前t个字符想匹配的t个字符就可以了。这样就减少了进程间的通信。其算法描述如下：&lt;/p&gt;&#xD;
&lt;p&gt;输入:主串T[0...n-1],模式串S[0...m-1]&lt;/p&gt;&#xD;
&lt;p&gt;输出：m[0...n-1],当m[i] = 1时，则主串S中匹配到模式串，且i为起始位置&lt;/p&gt;&#xD;
&lt;p&gt;条件：t个处理器&lt;/p&gt;&#xD;
&lt;p&gt;1）p0读取主串和模式串，将模式串广播到起到所有的处理器中，并将主串分段发送到其对应的处理器中&lt;/p&gt;&#xD;
&lt;p&gt;2）处理器并行计算next函数，这样每个处理器都有统一的next函数和模式串&lt;/p&gt;&#xD;
&lt;p&gt;3）处理器p0 ,p1,...,pt-1并行计算各自负责字符串的后m-1个字符的字串和模式串的最小匹配串，并将最小匹配串发往下一个处理器&lt;/p&gt;&#xD;
&lt;p&gt;4）处理器接收上个处理器发送的字符串，并和本身的字符串合并成一个新的字符串&lt;/p&gt;&#xD;
&lt;p&gt;5）各处理器并行计算匹配结果m&lt;/p&gt;&#xD;
&lt;p&gt;6）处理器p0对各处理器的匹配结果进行整合，得到最终结果。&lt;/p&gt;&#xD;
&lt;p&gt;因为kmp并行算法相对简单，也没有用到新的MPI函数，这里不列出其并行实现代码。&lt;/p&gt;&#xD;
&lt;p&gt;下一篇：图论：单源最短路径的并行算法&lt;/p&gt;&lt;img src="http://www.cnblogs.com/jiahaipeng/aggbug/1712335.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/15/1712335.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2010/04/10/1708820.html</id><title type="text">MPI并行编程系列三：并行正则采样排序PSRS</title><summary type="text">快速排序算法的效率相对较高，并行算法在理想的情况下时间复杂度可达到o(n)，但并行快速排序算法有一个严重的问题：会造成严重的负载不平衡，最差情况下算法的复杂度可达o(n^2)。本篇我们介绍一种基于均匀划分的负载平衡的并行排序算法------并行正则采样排序（Parallel Sorting by Regular Sampling）。 一、算法的基本思想  假设待排序的元素n个，处理器p个。  首先...</summary><published>2010-04-10T02:32:00Z</published><updated>2010-04-10T02:32:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/10/1708820.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/10/1708820.html"/><content type="html">&lt;p&gt;快速排序算法的效率相对较高，并行算法在理想的情况下时间复杂度可达到o(n)，但并行快速排序算法有一个严重的问题：会造成严重的负载不平衡，最差情况下算法的复杂度可达o(n^2)。本篇我们介绍一种基于均匀划分的负载平衡的并行排序算法------并行正则采样排序（Parallel Sorting by Regular Sampling）。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;一、算法的基本思想&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;假设待排序的元素n个，处理器p个。&lt;/p&gt; &lt;p&gt;首先将这n个元素均匀的分成p部分，每部分包含n/p个元素。每个处理器负责其中的一部分，并对其进行局部排序。为确定局部有序序列在整个序列中的位置，每个处理器从各自的局部有序序列中选取几个代表元素，将这些代表元素进行排序后选出p-1个主元。每个处理器根据这p-1个主元将自己的局部有序序列分成p段。然后通过全局交换的方式，将p段有序序列分发给对应的处理器，使第i个处理器都拥有各个处理器的第i段，共p段有序序列。每个处理器对着p段有序序列进行排序。最后，将各个处理器的有序段依次汇合起来，就是全局有序序列了。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;二、算法描述&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;根据算法的基本思想，我们对算法的描述如下：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;输入：n个待排序的序列&lt;/p&gt; &lt;p&gt;输出：分布在各个处理器上，得到全局有序的数据序列&lt;/p&gt; &lt;p&gt;1）无序序列的划分及局部排序&lt;/p&gt; &lt;p&gt;根据数据快的划分方法（请看系列一），将无序序列划分成p部分，每个处理器对其中的一部分进行串行快速排序，这样每个处理器就会拥有一个局部有序序列。&lt;/p&gt; &lt;p&gt;2）选取代表元素&lt;/p&gt; &lt;p&gt;每个处理器从局部有序序列中选取第w,2w,...,(p-1)w共p-1个代表元素。其中w = n/p^2。&lt;/p&gt; &lt;p&gt;3）确定主元&lt;/p&gt; &lt;p&gt;每个处理器都将自己选取好的代表元素发送给处理器p0。p0对这p段有序序列做多路归并排序，再从这排序后的序列中选取第p-1,2(p-1), ...,(p-1)(p-1)共p-1个元素作为主元。&lt;/p&gt; &lt;p&gt;4）分发主元&lt;/p&gt; &lt;p&gt;p0将这p-1个主元分发给各个处理器。&lt;/p&gt; &lt;p&gt;5）局部有序序列划分&lt;/p&gt; &lt;p&gt;每个处理器在接收到主元后，根据主元将自己的局部有序序列划分成p段。&lt;/p&gt; &lt;p&gt;6）p段有序序列的分发&lt;/p&gt; &lt;p&gt;每个处理器将自己的第i段发送给第i个处理器，是处理器i都拥有所有处理器的第i段。&lt;/p&gt; &lt;p&gt;7）多路排序&lt;/p&gt; &lt;p&gt;每个处理器将上一步得到的p段有序序列做多路归并。&lt;/p&gt; &lt;p&gt;经过这7步后，一次将每个处理器的数据取出，这些数据是有序的。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;strong&gt;三、算法分析&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp; &lt;/strong&gt;1）负载均衡分析：&lt;/p&gt; &lt;p&gt;因为这个算法是一个负载平衡的算法，者从第1）步中就可以看出来，但却不是完美的，因为在第6）步的划分很可能会引起负载的不平衡。&lt;/p&gt; &lt;p&gt;2）时间复杂度分析&lt;/p&gt; &lt;p&gt;PSRS算法适合处理大批量的数据（呵呵，数据量不大，何必并行乎）。当n&amp;gt;p^3时，算法的时间复杂度可达n/p*logn。具体每一步的时间复杂度的分析在这里就不一一描述了，因为每一步的排序都是普通的串行排序算法。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;四、算法实现&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;因为算法比较复杂，代码较长，本文仅仅列出主代码，代码如下：&lt;/p&gt; &lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt; psrs_mpi(&lt;span &gt;int&lt;/span&gt; *argc, &lt;span &gt;char&lt;/span&gt; ***argv){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; process_id;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; process_size;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *init_array;             &lt;span &gt;//初始数组&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; init_array_length;         &lt;span &gt;//初始数组长度&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *local_sample;             &lt;span &gt;//每个进程选取的代表元素数组&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; local_sample_length;    &lt;span &gt;//代表元素数组长度&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *sample;                 &lt;span &gt;//代表元素集合（0号进程使用）&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *sorted_sample;         &lt;span &gt;//排序后的代表元素的集合&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; sample_length;             &lt;span &gt;//代表预算的长度&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *primary_sample;         &lt;span &gt;//主元&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *resp_array;             &lt;span &gt;//偏移数组，主要用户指定个进程数组的各分段的长度&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *section_resp_array;    &lt;span &gt;//偏移数组,用于指定进程从其他进程获得的数组的长度&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *section_array;             &lt;span &gt;//从各个进程中获得分段数组的集合&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  23:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *sorted_section_array;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; section_array_length;     &lt;span &gt;//总长&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  25:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; section_index;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  27:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; i, j ;                     &lt;span &gt;//循环变量&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  29:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;    MPI_Request handle;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  31:  &lt;/span&gt;    MPI_Status  status;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  33:  &lt;/span&gt;    mpi_start(argc, argv, &amp;amp;process_size, &amp;amp;process_id, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;    resp_array = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * process_size);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  35:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;    &lt;span &gt;//为每个进程构建一个数组&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  37:  &lt;/span&gt;    &lt;span &gt;//并对改进型的数组进行串行快速排序&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  38:  &lt;/span&gt;    init_array_length = ARRAY_LENGTH;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  39:  &lt;/span&gt;    init_array = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * init_array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  40:  &lt;/span&gt;    array_builder_seed(init_array, init_array_length, process_id);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  41:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  42:  &lt;/span&gt;    quick_sort(init_array, 0, init_array_length -1);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  43:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  44:  &lt;/span&gt;    &lt;span &gt;//每个处理器从排序号的序列中选取process_size-1个元素&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  45:  &lt;/span&gt;    &lt;span &gt;//并发送到0号进程中&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  46:  &lt;/span&gt;    local_sample_length = process_size - 1;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  47:  &lt;/span&gt;    local_sample = array_sample(init_array, local_sample_length, init_array_length/process_size, process_id);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  48:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  49:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_id)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  50:  &lt;/span&gt;         MPI_Send(local_sample, local_sample_length, MPI_INT, 0, SAMPLE_DATA, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  51:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  52:  &lt;/span&gt;    &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  53:  &lt;/span&gt;    &lt;span &gt;//0号进程接收各处理器发送过来的代表元素，并将这些元素做多路归并排序&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  54:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(!process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  55:  &lt;/span&gt;        sample = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(0, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * process_size * local_sample_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  56:  &lt;/span&gt;        sorted_sample = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(0, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * process_size * local_sample_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  57:  &lt;/span&gt;        array_copy(sample, local_sample, local_sample_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  58:  &lt;/span&gt;        &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  59:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt;(i = 1; i &amp;lt; process_size; i++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  60:  &lt;/span&gt;            MPI_Irecv(sample + local_sample_length * i, local_sample_length, MPI_INT, i, SAMPLE_DATA,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  61:  &lt;/span&gt;                    MPI_COMM_WORLD, &amp;amp;handle); &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  62:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  63:  &lt;/span&gt;        MPI_Wait(&amp;amp;handle, &amp;amp;status);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  64:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  65:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt;(i = 0; i &amp;lt; process_size; i++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  66:  &lt;/span&gt;            resp_array[i] = local_sample_length;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  67:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  68:  &lt;/span&gt;        mul_merger(sample, sorted_sample, resp_array, process_size);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  69:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  70:  &lt;/span&gt;        &lt;span &gt;//从排序好的代表元素中选取process_size-1个主元,并将这些主元广播道其他的处理器中&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  71:  &lt;/span&gt;        primary_sample = array_sample(sorted_sample, process_size -1, process_size -1, process_id);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  72:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  73:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_id)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  74:  &lt;/span&gt;        primary_sample = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * process_size -1);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  75:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  76:  &lt;/span&gt;    MPI_Bcast(primary_sample, process_size-1, MPI_INT, 0, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  77:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  78:  &lt;/span&gt;    &lt;span &gt;//将处理器上的数据根据主元分成process_size 端&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  79:  &lt;/span&gt;    get_array_sepator_resp(init_array, primary_sample, resp_array, init_array_length, process_size); &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  80:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_id == ID){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  81:  &lt;/span&gt;        printf(&lt;span &gt;"process %d resp array is:"&lt;/span&gt; ,process_id);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  82:  &lt;/span&gt;        array_int_print(process_size, resp_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  83:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  84:  &lt;/span&gt;    &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  85:  &lt;/span&gt;    &lt;span &gt;//每个处理器将自己的第i段发送给第i个处理器&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  86:  &lt;/span&gt;    section_resp_array = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * process_size);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  87:  &lt;/span&gt;    section_resp_array[process_id] = resp_array[process_id];    &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  88:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  89:  &lt;/span&gt;    &lt;span &gt;//每个进程将要发送的数据的个数发送给哥哥处理器&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  90:  &lt;/span&gt;    &lt;span &gt;for&lt;/span&gt;(i = 0; i &amp;lt; process_size; i++){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  91:  &lt;/span&gt;        &lt;span &gt;if&lt;/span&gt;(i == process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  92:  &lt;/span&gt;            &lt;span &gt;for&lt;/span&gt;(j = 0; j &amp;lt; process_size; j++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  93:  &lt;/span&gt;               &lt;span &gt;if&lt;/span&gt;(i != j)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  94:  &lt;/span&gt;                      MPI_Send(&amp;amp;(resp_array[j]), 1, MPI_INT, j, SECTION_INDEX , &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  95:  &lt;/span&gt;                           MPI_COMM_WORLD); &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  96:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  97:  &lt;/span&gt;        &lt;span &gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  98:  &lt;/span&gt;            MPI_Recv(&amp;amp;(section_resp_array[i]), 1, MPI_INT, i, SECTION_INDEX,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  99:  &lt;/span&gt;                    MPI_COMM_WORLD, &amp;amp;status);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 100:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 101:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 102:  &lt;/span&gt;    MPI_Barrier(MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 103:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 104:  &lt;/span&gt;    section_array_length = get_array_element_total(section_resp_array, 0, process_size - 1);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 105:  &lt;/span&gt;    section_array = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * section_array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 106:  &lt;/span&gt;    sorted_section_array = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * section_array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 107:  &lt;/span&gt;    section_index = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 108:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 109:  &lt;/span&gt;    &lt;span &gt;for&lt;/span&gt;(i = 0; i &amp;lt; process_size; i++){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 110:  &lt;/span&gt;        &lt;span &gt;if&lt;/span&gt;(i == process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 111:  &lt;/span&gt;            &lt;span &gt;for&lt;/span&gt;(j = 0; j &amp;lt; process_size; j++){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 112:  &lt;/span&gt;                &lt;span &gt;if&lt;/span&gt;(j)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 113:  &lt;/span&gt;                    section_index = get_array_element_total(resp_array, 0 , j-1);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 114:  &lt;/span&gt;                &lt;span &gt;if&lt;/span&gt;(i == j)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 115:  &lt;/span&gt;                    array_int_copy(section_array, init_array, section_index, section_index+resp_array[j]);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 116:  &lt;/span&gt;                &lt;span &gt;if&lt;/span&gt;(i != j){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 117:  &lt;/span&gt;                    &lt;span &gt;if&lt;/span&gt;(j)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 118:  &lt;/span&gt;                        section_index = get_array_element_total(resp_array, 0 , j-1);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 119:  &lt;/span&gt;                    MPI_Send(&amp;amp;(init_array[section_index]), resp_array[j], MPI_INT,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 120:  &lt;/span&gt;                            j, SECTION_DATA, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 121:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 122:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 123:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 124:  &lt;/span&gt;        &lt;span &gt;else&lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 125:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt;(i)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 126:  &lt;/span&gt;                section_index = get_array_element_total(section_resp_array, 0, i-1);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 127:  &lt;/span&gt;            MPI_Recv(&amp;amp;(section_array[section_index]), section_resp_array[i], MPI_INT,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 128:  &lt;/span&gt;                    i, SECTION_DATA, MPI_COMM_WORLD, &amp;amp;status);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 129:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 130:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 131:  &lt;/span&gt;    MPI_Barrier(MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 132:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 133:  &lt;/span&gt;    &lt;span &gt;//进行多路归并排序&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 134:  &lt;/span&gt;    mul_merger(section_array, sorted_section_array, section_resp_array, process_size);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 135:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 136:  &lt;/span&gt;    array_int_print(section_array_length, sorted_section_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 137:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 138:  &lt;/span&gt;    &lt;span &gt;//释放内存&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 139:  &lt;/span&gt;    free(resp_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 140:  &lt;/span&gt;    free(init_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 141:  &lt;/span&gt;    free(local_sample);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 142:  &lt;/span&gt;    free(primary_sample);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 143:  &lt;/span&gt;    free(section_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 144:  &lt;/span&gt;    free(sorted_section_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 145:  &lt;/span&gt;    free(section_resp_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 146:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 147:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(!process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 148:  &lt;/span&gt;        free(sample);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 149:  &lt;/span&gt;        free(sorted_sample);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 150:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 151:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 152:  &lt;/span&gt;    MPI_Finalize();&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; 153:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;strong&gt;五、MPI函数分析&lt;/strong&gt;&lt;/pre&gt;&lt;pre&gt;&lt;strong&gt; &lt;/strong&gt;&lt;/pre&gt;&lt;pre&gt;&lt;strong&gt;     &lt;/strong&gt;在上述算法中，用到了MPI的非阻塞通信函数：MPI_IRecv，其对应的是MPI_Isend。这连个函数用于进程间的非阻塞通信，使通信和运算能够同时进行。有这两&lt;/pre&gt;&lt;pre&gt;个非阻塞通信函数，就不能不提MPI_Wait函数，该函数的作用是阻塞进程执行，直到想对应的所有进程操作都执行的这个地方为止。一般是这个三函数一起使用。&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;下篇，我们将介绍kmp字符串匹配算法及其并行化。&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/jiahaipeng/aggbug/1708820.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/10/1708820.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2010/04/10/1708818.html</id><title type="text">MPI并行编程系列</title><summary type="text">为提高自己的MPI编程水平，并能及时总结MPI编程的认识，特写此系列文章。欢迎各位高手积极指导，不吝赐教。  本系列是根据陈国良院士的《并行算法实践》一书进行学习和编写。  本系列中的所有程序都是自己用心编写，并测试通过。  程序编写环境：  操作系统：Ubuntu 语言： c 并行库： MPI 编译器： gcc 编写工具：vim  本系列主要包括一下内容  一、排序算法及并行化  1）枚举排序及...</summary><published>2010-04-10T02:29:00Z</published><updated>2010-04-10T02:29:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/10/1708818.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/10/1708818.html"/><content type="html">&lt;p&gt;为提高自己的MPI编程水平，并能及时总结MPI编程的认识，特写此系列文章。欢迎各位高手积极指导，不吝赐教。&lt;/p&gt; &lt;p&gt;本系列是根据陈国良院士的《并行算法实践》一书进行学习和编写。&lt;/p&gt; &lt;p&gt;本系列中的所有程序都是自己用心编写，并测试通过。&lt;/p&gt; &lt;p&gt;程序编写环境：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;操作系统：Ubuntu&lt;/p&gt; &lt;p&gt;语言：&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; c&lt;/p&gt; &lt;p&gt;并行库：&amp;nbsp;&amp;nbsp; MPI&lt;/p&gt; &lt;p&gt;编译器：&amp;nbsp; gcc&lt;/p&gt; &lt;p&gt;编写工具：vim&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;本系列主要包括一下内容&lt;/p&gt; &lt;p&gt;一、排序算法及并行化&lt;/p&gt; &lt;p&gt;1）&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/05/1704493.html"&gt;枚举排序及并行化&lt;/a&gt;&lt;/p&gt; &lt;p&gt;2）&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/06/1705050.html"&gt;快速排序及并行化&lt;/a&gt;&lt;/p&gt; &lt;p&gt;3）&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/10/1708820.html"&gt;并行正则采样排序&lt;/a&gt;&lt;/p&gt; &lt;p&gt;二、字符串匹配&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/15/1712335.html"&gt;1）KMP算法及并行化&lt;/a&gt;&lt;/p&gt; &lt;p&gt;三、图&lt;/p&gt; &lt;p&gt;1）&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/19/1715115.html"&gt;单源最短路径&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/jiahaipeng/aggbug/1708818.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/10/1708818.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2010/04/06/1705050.html</id><title type="text">MPI并行编程系列二：快速排序</title><summary type="text">在上一篇中对枚举排序的MPI并行算法进行了详细的描述和实现，算法相对简单，采用了并行编程模式中的单程序多数据流的并行编程模式。在本篇中，将对快速排序进行并行化分析和实现。本篇代码用到了上篇中的几个公用方法，在本篇中将不再做说明。  在本篇中，我们首先对快速排序算法进行描述和实现，并在此基础上分析此算法的并行性，确定并行编程模式，最后给出该算法的MPI实现。 一、快速排序算法说明  快速排序时一种最...</summary><published>2010-04-06T01:00:00Z</published><updated>2010-04-06T01:00:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/06/1705050.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/06/1705050.html"/><content type="html">&lt;p&gt;在上一篇中对枚举排序的MPI并行算法进行了详细的描述和实现，算法相对简单，采用了并行编程模式中的单程序多数据流的并行编程模式。在本篇中，将对快速排序进行并行化分析和实现。本篇代码用到了上篇中的几个公用方法，在本篇中将不再做说明。&lt;/p&gt; &lt;p&gt;在本篇中，我们首先对快速排序算法进行描述和实现，并在此基础上分析此算法的并行性，确定并行编程模式，最后给出该算法的MPI实现。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;一、快速排序算法说明&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/strong&gt;快速排序时一种最基本的排序算法，效率相对较高。其基本思想是：在当前无序数组R[1,n]中选取一个记录作为比较的“基准”，即作为排序中的“轴”。经过一趟排序后，当前无序数组R[1,n]就会以这个轴为核心划分为两个无序的子区r1[1,i-1],r2[i,n]。其中左边的无序子区都会比“轴”小，右边的无序子区都会比“轴”大。这样下一趟排序，我们就可以对这两个子区用同样的方法进行划分排序，知道所有的无序子区中的记录均排好为止。&lt;/p&gt; &lt;p&gt;根据算法的说明，快速排序时一个典型的递归算法，算法描述如下：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;无序数组R[1], R[2], ... , R[n]&lt;/p&gt; &lt;p&gt;quick_sort(R, start, end)&lt;/p&gt; &lt;p&gt;if(start &amp;lt; end)&lt;/p&gt; &lt;p&gt;r = partion(R, start, end)&lt;/p&gt; &lt;p&gt;quick_sort(R, start, r-1)&lt;/p&gt; &lt;p&gt;quick_sort(R, r+1, end)&lt;/p&gt; &lt;p&gt;endif&lt;/p&gt; &lt;p&gt;end quick_sort&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;方法partion的作用就是选取“轴”，并将数组分为两个无序子区，并将该“轴”的最终位置返回，在这里我们选择数组的第一个元素为“轴”，其算法描述为：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;partion(R, start, end)&lt;/p&gt; &lt;p&gt;r = R[start]&lt;/p&gt; &lt;p&gt;while(start &amp;lt; end)&lt;/p&gt; &lt;p&gt;while( (R[end] &amp;gt;= r) &amp;amp;&amp;amp; (start &amp;lt; end))&lt;/p&gt; &lt;p&gt;end--&lt;/p&gt; &lt;p&gt;end ehile&lt;/p&gt; &lt;p&gt;R[start] = R[end]&lt;/p&gt; &lt;p&gt;while( (R[start] &amp;lt; r) &amp;amp;&amp;amp; (start &amp;lt; end))&lt;/p&gt; &lt;p&gt;start++&lt;/p&gt; &lt;p&gt;end wile&lt;/p&gt; &lt;p&gt;R[end] = R[start]&lt;/p&gt; &lt;p&gt;end while &lt;/p&gt; &lt;p&gt;R[start] = r&lt;/p&gt; &lt;p&gt;return start&lt;/p&gt; &lt;p&gt;end partion&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;该排序算法的性能好坏主要取决于“轴”的选定，即无序数组的划分是否均衡。最好的情况下，无序数组每次都会被划为两个均等的无序子区，这是算法的负责度为o(nlogn)；最坏的情况，无序数组每次划分都是左边n-1个元素，右边0个元素，这时算法的复杂度为o(n^2)。在通常的情况下，该算法的复杂度会依然保持在o(nlogn)，上只不过具有更高的常数因子。因此，选定一个有效地“轴”，成为该算法的关键。一般情况下，会选定无序数组的第一个，中间或者是最后一个元素作为算法的“轴”，我们可以对着三个元素进行比较，取大小居中的那个元素作为该算法的“轴”。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;二、快速排序算法的串行实现&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;快速排序很明显的是一个递归的程序。编写递归程序一个很重的要点就是确定在什么条件下终止递归操作。主函数代码如下：&lt;/p&gt; &lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt; quick_sort_function(&lt;span &gt;int&lt;/span&gt; *array, &lt;span &gt;int&lt;/span&gt; start, &lt;span &gt;int&lt;/span&gt; last){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; part_position;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(start &amp;gt;= last)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        &lt;span &gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;    part_position = part_array_head(array, start, last);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;    quick_sort_function(array, start, part_position-1);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    quick_sort_function(array, part_position+1, last);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;主函数代码很简单，一个终止递归的条件，一个递归方式。在主函数中，核心函数为part_array_head,其代码如下：&lt;/pre&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  i&lt;/span&gt;nt part_array_head(&lt;span &gt;int&lt;/span&gt; *array, &lt;span &gt;int&lt;/span&gt; start, &lt;span &gt;int&lt;/span&gt; last){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; position_value = array[start];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;    &lt;span &gt;while&lt;/span&gt;(start &amp;lt; last){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        &lt;span &gt;while&lt;/span&gt;(start &amp;lt; last &amp;amp;&amp;amp; array[last] &amp;gt;= position_value)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;            last--;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        array[start] = array[last];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        &lt;span &gt;while&lt;/span&gt;(start &amp;lt; last &amp;amp;&amp;amp; array[start] &amp;lt;= position_value)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;            start++;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;        array[last] = array[start];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;    array[start] = position_value;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;    &lt;span &gt;return&lt;/span&gt; start; &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;从代码可以看出，快速排序的代码相对姜丹，总共不过三十行代码。本人是非常喜欢递归操作的。下面我们将对快速排序进行并行化分析。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;三、快速排序并行化分析&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;在并行编程策略中，有一种策略非常适合递归算法，自然也就成为我们快速排序并行化的首选策略。这种策略为“分治策略”，这种策略的核心思想就是将一个大而复杂的问题分解成若干个子问题分而治之。若分解后的子问题依然过大或者是过于复杂，则可反复利用分治策略，直到很容易的求解子问题未知。&lt;/p&gt;&#xD;
&lt;p&gt;有此看出，分治策略也符合递归的思想。要实现分治策略，主要分为三步：1、将大问题分解成小问题；2、求解小问题；3、归并小问题的解，得到最终结果。其中各个小问题的求解就是我们并行化的所在。分治策略的说明图如下：&lt;/p&gt;&#xD;
&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/jiahaipeng/WindowsLiveWriter/832a19ad640d_92F7/image_4.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/jiahaipeng/WindowsLiveWriter/832a19ad640d_92F7/image_thumb_1.png" width="244" height="173"&gt;&lt;/a&gt; &lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt;&#xD;
&lt;p&gt;在快速排序算法中，我们就是将原无序数组按照一定得规则拆分成一个个子数组，即上图中的“分解”过程，每个子数组的排序可并行执行。当各子数组排序完毕后，依此将结构传给其父数组，得到最终的结果，即上图中的“归并”过程。&lt;/p&gt;&#xD;
&lt;p&gt;基于以上的分析，我们给出快速排序算法MPI的实现如下：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;四、快速排序的MPI并行实现&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/strong&gt;因为分治策略的特殊性，我们进行快速排序算法的进程数目为2^m个。我们依然用进程p0来读取原数组，最终的排序结果也会由进程p0打印出来。&amp;nbsp; &lt;/p&gt;&#xD;
&lt;p&gt;在该算法中，我们如果知道进程数目为2^m个，就应该能够求出m。因此我写了一个实现函数，求一个整数的以2为底的对数的算法。该算法的具体实现为：&lt;/p&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;int&lt;/span&gt; log_int(&lt;span &gt;int&lt;/span&gt; root, &lt;span &gt;int&lt;/span&gt; num){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; i, j;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;    i = 1;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    j = root;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;    &lt;span &gt;while&lt;/span&gt;(j &amp;lt; num){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;        j *= root;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        i++;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(j &amp;gt; num)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;        i--;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;    &lt;span &gt;return&lt;/span&gt; i;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;该并行算法的主函数为：&lt;/p&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt; quick_sort_mpi(&lt;span &gt;int&lt;/span&gt; *argv, &lt;span &gt;char&lt;/span&gt; ***argc){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; process_id;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; process_size;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *init_array;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; array_length;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; log_num;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; k;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    mpi_start(argv, argc, &amp;amp;process_size, &amp;amp;process_id, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_size % 2 != 0){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;        &lt;span &gt;if&lt;/span&gt;(!process_id)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;            printf(&lt;span &gt;"the size of the process must is the multipe of 2"&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;        MPI_Abort(MPI_COMM_WORLD, PROCESS_SIZE_ERROR);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;    log_num = log_int(2, process_size); &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;    array_length = ARRAY_LENGTH;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(!process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  25:  &lt;/span&gt;        init_array = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(0, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;        array_builder(init_array, array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  27:  &lt;/span&gt;        array_int_print(array_length, init_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  29:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;    &lt;span &gt;//对数组进行快速排序&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  31:  &lt;/span&gt;    quick_sort_mpi_function(init_array, array_length, log_num, process_id, 0, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  33:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(!process_id)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;        array_int_print(array_length, init_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  35:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;    MPI_Finalize();&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  37:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;在程序中出现的子函数在这里就不一一介绍了，其中主要的函数在上一篇枚举排序的MPI算法中都有所介绍。主函数的核心就是quic_sort_mpi_fuction函数，&lt;/pre&gt;&lt;pre&gt;该函数真正实现了快速排序，其代码如下：&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt; quick_sort_mpi_function(&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; *init_array,             &lt;span &gt;//待排序数组&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; array_length,             &lt;span &gt;//待排序数组长度&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; log_num,                 &lt;span &gt;//进程数取2为底的对数&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; process_id,             &lt;span &gt;//当前活动进程ID&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; part_process_id,         &lt;span &gt;//对数组进行拆分的进程ID&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;        MPI_Comm comm){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *local_array;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; local_array_length = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; send_array_length;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; partion_position;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;    &lt;span &gt;//取得要接收数据的进程号的进程号&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; receive_process_id; &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; j;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;    MPI_Status status;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(log_num == 0){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  23:  &lt;/span&gt;        &lt;span &gt;if&lt;/span&gt;(process_id == part_process_id &amp;amp;&amp;amp; array_length &amp;gt; 1)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;                quick_sort_function(init_array, 0, array_length-1);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  25:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;        &lt;span &gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  27:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  29:  &lt;/span&gt;    receive_process_id = part_process_id + pow_int(2, log_num - 1);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  31:  &lt;/span&gt;    &lt;span &gt;//当活动进程为数组拆分进程时，按照快速排序方法对数组分成两部分&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_id == part_process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  33:  &lt;/span&gt;        partion_position = part_array_head(init_array, 0, array_length-1); &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;        send_array_length = array_length - partion_position -1;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  35:  &lt;/span&gt;        local_array_length = partion_position;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  37:  &lt;/span&gt;        MPI_Send((&lt;span &gt;void&lt;/span&gt; *)&amp;amp;send_array_length, 1, MPI_INT, &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  38:  &lt;/span&gt;                receive_process_id, LENGTH_MESSAGE, comm);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  39:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  40:  &lt;/span&gt;        &lt;span &gt;if&lt;/span&gt;(send_array_length &amp;gt; 0)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  41:  &lt;/span&gt;            MPI_Send((&lt;span &gt;void&lt;/span&gt; *)(init_array + partion_position +1), send_array_length,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  42:  &lt;/span&gt;                    MPI_INT, receive_process_id, DATA_MESSAGE, comm);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  43:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  44:  &lt;/span&gt;    &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  45:  &lt;/span&gt;    &lt;span &gt;//当活动进程为待接收数据的进程时，接收从拆分进程发送过来的数据&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  46:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_id == receive_process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  47:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  48:  &lt;/span&gt;        MPI_Recv((&lt;span &gt;void&lt;/span&gt; *)&amp;amp;local_array_length, 1, MPI_INT, part_process_id,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  49:  &lt;/span&gt;                LENGTH_MESSAGE, comm, &amp;amp;status);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  50:  &lt;/span&gt;         &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  51:  &lt;/span&gt;        &lt;span &gt;if&lt;/span&gt;(local_array_length &amp;gt;0)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  52:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  53:  &lt;/span&gt;            local_array = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * local_array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  54:  &lt;/span&gt;            MPI_Recv((&lt;span &gt;void&lt;/span&gt; *)local_array, local_array_length, MPI_INT, part_process_id,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  55:  &lt;/span&gt;                    DATA_MESSAGE, comm, &amp;amp;status);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  56:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  57:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  58:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  59:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  60:  &lt;/span&gt;    j = local_array_length;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  61:  &lt;/span&gt;    MPI_Bcast(&amp;amp;j, 1, MPI_INT, part_process_id, comm);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  62:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(j &amp;gt; 1){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  64:  &lt;/span&gt;        quick_sort_mpi_function(init_array, local_array_length, log_num -1, &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  65:  &lt;/span&gt;                process_id, part_process_id, comm);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  66:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  67:  &lt;/span&gt;    &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  68:  &lt;/span&gt;    j = local_array_length;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  69:  &lt;/span&gt;    MPI_Bcast(&amp;amp;j, 1, MPI_INT, receive_process_id, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  70:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(j &amp;gt; 1)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  71:  &lt;/span&gt;        quick_sort_mpi_function(local_array, local_array_length, log_num-1,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  72:  &lt;/span&gt;                process_id, receive_process_id, comm);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  73:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  74:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_id == receive_process_id &amp;amp;&amp;amp; local_array_length &amp;gt;0)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  75:  &lt;/span&gt;        MPI_Send((&lt;span &gt;void&lt;/span&gt; *)local_array, local_array_length, MPI_INT,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  76:  &lt;/span&gt;                part_process_id, DATA_MESSAGE_SORT, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  77:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  78:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(process_id == part_process_id &amp;amp;&amp;amp; send_array_length &amp;gt; 0)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  79:  &lt;/span&gt;        MPI_Recv((&lt;span &gt;void&lt;/span&gt; *)(init_array + partion_position +1), send_array_length,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  80:  &lt;/span&gt;                MPI_INT, receive_process_id, DATA_MESSAGE_SORT, MPI_COMM_WORLD, &amp;amp;status);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  81:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;该算法基本继承了并行编程策略的分治所发思想：分解 --- 求解 --- 归并。&lt;/pre&gt;&lt;pre&gt;&lt;strong&gt;五、MPI函数的说明&lt;/strong&gt;&lt;/pre&gt;&lt;pre&gt;在该算法中，用到了MPI两个重要的通信函数MPI_Send和MPI_Recv，发送和接受函数。这两个函数实现了两个进程间的通信。同时，这两个函数是阻塞通信函数，即：&lt;/pre&gt;&lt;pre&gt;进程在没有接受到或发送完数据的情况下，将阻塞。&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;这样我们就完成了快速排序算法并行化得描述和实现，在这两篇中，分别介绍了并行编程策略的两个策略：单程序多数据流策略和分治策略。下篇将介绍并行正则采样&lt;/pre&gt;&lt;pre&gt;排序算法的设计和实现。&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&lt;img src="http://www.cnblogs.com/jiahaipeng/aggbug/1705050.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/06/1705050.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2010/04/05/1704493.html</id><title type="text">MPI并行编程系列一：枚举排序</title><summary type="text">前言  貌似有一年多的时间没有在博客园上发过随笔了。原因有三：1、懒，这是最主要的原因。哎，人老了，心和手也都老了。， 2、时间紧，也许这个理由这叫做借口。拿没时间作为任何事情的借口都是站不住脚的，我一直是这么认为的。但当时的确是特殊情况：原本计划一年完成的项目因为特殊原因必须在两个半月内完成。曾记得那时候从早上到晚上没有任何节假日的工作时的痛苦和激情，也忘不了项目成功上线后的喜悦和成就感。孙中山...</summary><published>2010-04-05T00:06:00Z</published><updated>2010-04-05T00:06:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/05/1704493.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/05/1704493.html"/><content type="html">&lt;p&gt;&lt;strong&gt;前言&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/strong&gt;貌似有一年多的时间没有在博客园上发过随笔了。原因有三：1、懒，这是最主要的原因。哎，人老了，心和手也都老了。&lt;img alt="" src="http://www.zu14.cn/coolemotion/emotions/tang_19.png"&gt;， 2、时间紧，也许这个理由这叫做借口。拿没时间作为任何事情的借口都是站不住脚的，我一直是这么认为的。但当时的确是特殊情况：原本计划一年完成的项目因为特殊原因必须在两个半月内完成。曾记得那时候从早上到晚上没有任何节假日的工作时的痛苦和激情，也忘不了项目成功上线后的喜悦和成就感。孙中山先生解释什么为革命的时候，说过：要享文明之幸福，不得不经文明之痛苦，这痛苦就是革命。我深有感触，同样要享成功之喜悦，不得不经成功之痛苦，这痛苦就是奋斗。3、转行。说转行也不太合适。从事了近两年的Web系统的开发后，导师让我研究并行计算，学好MPI编程，固最近一直在MPI中游荡。说实话，我并不确定这篇文章发在博客园中是否合适，因为博客园是.net社区。但我在别的技术社区中实在是找不到博客园的感觉，所以还是发在博客园中吧。希望博客园中的并行程序设计高手给指点一二。&lt;/p&gt; &lt;p&gt;以后我会从易到难写MPI程序设计的一系列的例子，开篇算法为枚举排序并行算法。&lt;/p&gt; &lt;p&gt;编程环境如下：操作系统：Ubuntu， 编程语言 c， 并行库 MPI， 编译器 gcc&lt;/p&gt; &lt;p&gt;&lt;strong&gt;一、枚举排序算法说明：&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/strong&gt;枚举排序（Enumeration Sort）是一种最为简单的排序算法，通常也被叫做秩排序（Rank Sort）。&lt;/p&gt; &lt;p&gt;该算法的基本思想是：对每一个要排序的元素统计小于它的所有元素的个数，从而得到该元素在整个序列中的位置。其时间复杂度为o(n^2)。其伪代码为：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;输入为：a[1], a[2] , ... , a[n]&lt;/p&gt; &lt;p&gt;输出为：b[1], b[2] , ..., b[n]&lt;/p&gt; &lt;p&gt;for i =1 to n do&lt;/p&gt; &lt;p&gt;1)k =1&lt;/p&gt; &lt;p&gt;2)for j = 1 to n do&lt;/p&gt; &lt;p&gt;if a[i] &amp;gt; a[j] then&lt;/p&gt; &lt;p&gt;k= k + 1&lt;/p&gt; &lt;p&gt;endif&lt;/p&gt; &lt;p&gt;endfor&lt;/p&gt; &lt;p&gt;3)b[k] = a[i]&lt;/p&gt; &lt;p&gt;endfor&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;算法思想很简单，现将其主要代码总结如下：&lt;/p&gt; &lt;p&gt;1、数组自动生成，随机生成长度为n的数组：&lt;/p&gt; &lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt; array_builder(&lt;span &gt;int&lt;/span&gt; *a, &lt;span &gt;int&lt;/span&gt; n)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; i;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;    srand((&lt;span &gt;int&lt;/span&gt;)time(0));&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;    &lt;span &gt;for&lt;/span&gt;(i = 0; i &amp;lt; n; i++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        a[i] = (&lt;span &gt;int&lt;/span&gt;)rand() % 100;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;    &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    &lt;span &gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;2、取得每个元素在数组中的秩，即统计每个元素按小于它的其他所有元素的个数：&lt;/pre&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;int&lt;/span&gt; *get_array_elem_position(&lt;span &gt;int&lt;/span&gt; *init_array, &lt;span &gt;int&lt;/span&gt; array_length, &lt;span &gt;int&lt;/span&gt; start, &lt;span &gt;int&lt;/span&gt; size){&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; i,j,k;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *position;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    position = (&lt;span &gt;int&lt;/span&gt; *)my_malloc(&lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * size);&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;    &lt;span &gt;for&lt;/span&gt;(i = start; i &amp;lt; start+size; i++){&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        k = 0;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt;(j = 0; j &amp;lt; array_length; j++){&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt;(init_array[i] &amp;lt; init_array[j])&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;                k++;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt;((init_array[i] == init_array[j]) &amp;amp;&amp;amp; i &amp;gt;j)&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;                k++;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;        }&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;        position[i-start] = k;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;    }&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;    &lt;span &gt;return&lt;/span&gt; position;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;其中my_malloc函数的作用为动态分配大小为size的空间，如分配失败，则终止程序：&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt; *my_malloc(&lt;span &gt;int&lt;/span&gt; malloc_size){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;    &lt;span &gt;void&lt;/span&gt; *buffer;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;((buffer = (&lt;span &gt;void&lt;/span&gt; *)malloc((size_t)malloc_size)) == NULL){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;        printf(&lt;span &gt;"malloc failure"&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;        exit(EXIT_FAILURE);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;    &lt;span &gt;return&lt;/span&gt; buffer;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;3、 算法主函数：&lt;/pre&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt; serial(){&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; i;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; array_length = ARRAY_LENGTH;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *init_array;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *sort_array;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *position;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;&lt;span &gt;//    array_length = get_array_length(4);&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    sort_array = (&lt;span &gt;int&lt;/span&gt; *)my_malloc(&lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * array_length);&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;    init_array = (&lt;span &gt;int&lt;/span&gt; *)my_malloc(&lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * array_length);&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;    array_builder(init_array, array_length);&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;    position = get_array_elem_position(init_array, array_length, 0, array_length);&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;    &lt;span &gt;for&lt;/span&gt;(i = 0; i &amp;lt; array_length; i++)&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;        sort_array[position[i]] = init_array[i];&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;    printf(&lt;span &gt;"串行实行结果:\n"&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  23:  &lt;/span&gt;    init_sort_array_print(init_array, sort_array, array_length);&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;} &lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;其中的数组打印函数就不列出来了。&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;strong&gt;二、枚举排序并行化分析&lt;/strong&gt;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;strong&gt;    &lt;/strong&gt;该算法的并行化算法比较的简单，一般的并行化无非就为数据并行和功能并行。显然该算法适合数据并行算法。即：如果我们有n个处理器，则我们将数据平均&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;pre&gt;分为n份，让每个处理器来处理其中一份数据。该算法的描述为：&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;pre&gt;输入：a[1], ... , a[n]&lt;/pre&gt;&lt;pre&gt;输入：b[1], ... , b[n]&lt;/pre&gt;&lt;pre&gt;1)进程p0将数组广播到所有进程中&lt;/pre&gt;&lt;pre&gt;2)每个进程对其相应的数组分块计算其中每个元素的秩&lt;/pre&gt;&lt;pre&gt;3）p0收集各进程的中相应元素的秩，并给出最终的排序结果。&lt;/pre&gt;&lt;/blockquote&gt;&lt;pre&gt;算法分析：假设我们在排序中用了m个处理器，则算法的复杂度为o（n^2/m),通信复杂度为o（mn）。&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;strong&gt;三、并行算法实现&lt;/strong&gt;&lt;/pre&gt;&lt;pre&gt;并行程序设计中一般分为四步：划分，通信，聚集和映射。&lt;/pre&gt;&lt;pre&gt;1、划分是将一个大任务划分为一系列小任务的过程。在本例中，计算每个元素的秩是互不相关的，因此我们可以将该任务划分为n个小任务，每个任务的作用就是&lt;/pre&gt;&lt;pre&gt;计算其中一个元素的秩。&lt;/pre&gt;&lt;pre&gt;2、通信就是要确定个进程的通信模式。在本例中，进程间的通信主要是进程p0将原始数组广播到各个进程中，同时收集各个进程的计算结果。&lt;/pre&gt;&lt;pre&gt;3、聚集。如果有m个进程，我们可以将这n个小任务聚集为m个原始任务，每个进程执行其中的一个原始任务。&lt;/pre&gt;&lt;pre&gt;4、映射。映射是将原始任务映射到各处理器的过程。这里由于没有使用集群，固映射为系统自动。&lt;/pre&gt;&lt;pre&gt;该算法的一个重要问题就是如何对数据分块，即上面第三步中，如何经n个小任务聚集成m个原始任务。我们的数据分块策略为：按块数据分解，这就意味着我们将&lt;/pre&gt;&lt;pre&gt;数组分为m个连续的快，每个块的大小基本相等。在对数组进行分解的过程中，我们必须要确定两个问题：1、给出进程，能够算出该进程所负责的数据。2、给出数据，&lt;/pre&gt;&lt;pre&gt;能够计算出该数据被那个一进程所负责。我们将这两个问题定义在头文件中：&lt;/pre&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;//n为数组长度，p为进程数，id为进城id&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;&lt;span &gt;#define&lt;/span&gt; BLOCK_LOW(id, p, n) ((id)*(n)/(p))&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;&lt;span &gt;#define&lt;/span&gt; BLOCK_HIGH(id, p, n) (BLOCK_LOW((id)+1, p, n)-1)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&lt;span &gt;#define&lt;/span&gt; BLOCK_SIZE(id, p, n) (BLOCK_HIGH(id, p, n) - BLOCK_LOW(id, p, n) + 1)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;&lt;span &gt;#define&lt;/span&gt; BLOCK_OWNER(j, p, n) (((P) * ((j) +1)-1)/(n))&lt;/pre&gt;&lt;pre&gt;并行程序为：&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;#include &lt;span &gt;"mpi.h"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;#include &lt;span &gt;"my_mpi.h"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;#include &lt;span &gt;"common.h"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;#include &lt;span &gt;"sort/enum_sort.h"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt;  mpi_sort(&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; *argc,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;        &lt;span &gt;char&lt;/span&gt; ***argv){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; process_id;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; process_size;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *count;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *resp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; array_low;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; array_size;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *local_position;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  23:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *position;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  25:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *sort_array;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; *init_array;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  27:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; array_length = ARRAY_LENGTH;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  29:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; i;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  31:  &lt;/span&gt;    my_mpi_struct mpi_struct;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  33:  &lt;/span&gt;    mpi_start(argc, argv, &amp;amp;process_size, &amp;amp;process_id, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  35:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(!process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;        position = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(0, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  37:  &lt;/span&gt;        sort_array = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(0, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  38:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  39:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  40:  &lt;/span&gt;    init_array = (&lt;span &gt;int&lt;/span&gt; *) my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  41:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(!process_id)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  42:  &lt;/span&gt;        array_builder(init_array, array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  43:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  44:  &lt;/span&gt;    MPI_Bcast(init_array, array_length, MPI_INT, 0, MPI_COMM_WORLD);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  45:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  46:  &lt;/span&gt;    array_low = BLOCK_LOW(process_id, process_size, array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  47:  &lt;/span&gt;    array_size = BLOCK_SIZE(process_id, process_size, array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  48:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  49:  &lt;/span&gt;    get_my_mpi_struct(&amp;amp;mpi_struct, process_id, process_size, array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  50:  &lt;/span&gt;    get_resp_count_array(&amp;amp;resp, &amp;amp;count, mpi_struct);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  51:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  52:  &lt;/span&gt;    local_position = get_array_elem_position(init_array, array_length, &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  53:  &lt;/span&gt;            array_low, array_size);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  54:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  55:  &lt;/span&gt;    MPI_Gatherv(local_position, array_size, MPI_INT, position, count, resp,&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  56:  &lt;/span&gt;           MPI_INT, 0, MPI_COMM_WORLD);    &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  57:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  58:  &lt;/span&gt;    &lt;span &gt;if&lt;/span&gt;(!process_id){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  59:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt;(i = 0; i&amp;lt; array_length; i++)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  60:  &lt;/span&gt;            sort_array[position[i]] = init_array[i];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  61:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  62:  &lt;/span&gt;        printf(&lt;span &gt;"the result of mpi:\n"&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  63:  &lt;/span&gt;        init_sort_array_print(init_array, sort_array, array_length);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  64:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  65:  &lt;/span&gt;        free(sort_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  66:  &lt;/span&gt;        free(position);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  67:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  68:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  69:  &lt;/span&gt;    free(count);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  70:  &lt;/span&gt;    free(resp);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  71:  &lt;/span&gt;    free(local_position);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  72:  &lt;/span&gt;    free(init_array);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  73:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  74:  &lt;/span&gt;    MPI_Finalize();&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  75:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  76: &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt; &lt;/span&gt; 其中mpi_start函数就是将编写MPI程序时三个必须函数MPI_Init,MPI_Comm_rank和MPI_Comm_size给写在一个函数中了，方便调用。&lt;/pre&gt;&lt;pre&gt;函数get_resp_count_array的作用是计算MPI收集函数所需要的偏移和组大小数组，其代码如下：&lt;/pre&gt;&#xD;
&lt;div &gt;&lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;void&lt;/span&gt; get_resp_count_array(&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; **resp,                 &lt;span &gt;//the resp array &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; **count,                 &lt;span &gt;//the count array&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;        my_mpi_struct mpi_struct){ &lt;span &gt;//my mpi struct&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; i;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; process_id = mpi_struct -&amp;gt; process_id;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; process_size = mpi_struct -&amp;gt; process_size;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;    &lt;span &gt;int&lt;/span&gt; number_count = mpi_struct -&amp;gt; number_count;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;    *resp = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * process_size);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;    *count = (&lt;span &gt;int&lt;/span&gt; *)my_mpi_malloc(process_id, &lt;span &gt;sizeof&lt;/span&gt;(&lt;span &gt;int&lt;/span&gt;) * process_size); &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;    (*resp)[0] = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;    (*count)[0] = BLOCK_SIZE(0, process_size, number_count);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;    &lt;span &gt;for&lt;/span&gt;(i = 1; i &amp;lt; process_size; i++){&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;        (*resp)[i] = (*resp)[i-1] + (*count)[i-1];&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;        (*count)[i] = BLOCK_SIZE(i, process_size, number_count);&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;}    &lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&lt;pre&gt;&lt;strong&gt;四、MPI主要函数说明&lt;/strong&gt;&lt;/pre&gt;&lt;pre&gt;&lt;strong&gt;    &lt;/strong&gt;在本例中一共用到了两个主要的MPI函数：MPI_Bcast和MPI_Gatherv。即一个广播函数和一个收集函数。&lt;/pre&gt;&lt;pre&gt;MPI_Bcast是一个组通信操作，用来完成一个进程向通信域中所有的进程广播消息&lt;/pre&gt;&lt;pre&gt;MPI_Gatherv是完成收集的组通信函数。跟进程从进程i收集count[i]个元素，并将手机的i个元素放在接收缓冲区的resp[i]个位置开始的地方。&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;strong&gt;五、后记&lt;/strong&gt;&lt;/pre&gt;&lt;pre&gt;这个MPI程序中一个比较简单的例子，作为我下MPI并行程序的一个开端。还请各位高手积极拍砖。&lt;/pre&gt;&lt;pre&gt;下篇将对快速排序的并行算法进行简单的介绍和实现。&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&lt;pre&gt;&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&lt;img src="http://www.cnblogs.com/jiahaipeng/aggbug/1704493.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/jiahaipeng/archive/2010/04/05/1704493.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2008/12/22/1360114.html</id><title type="text">c#基础（一）之内存管理</title><summary type="text">C#基础之内存管理，我觉得基础很重要......</summary><published>2008-12-22T14:19:00Z</published><updated>2008-12-22T14:19:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2008/12/22/1360114.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2008/12/22/1360114.html"/></entry><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2008/12/17/1356988.html</id><title type="text">用Windows Live Writer 首发Blog</title><summary type="text">首篇Windos Live Writer 博客，Windows live Writer 配置及其他</summary><published>2008-12-17T09:41:00Z</published><updated>2008-12-17T09:41:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2008/12/17/1356988.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2008/12/17/1356988.html"/></entry><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2008/12/15/1355543.html</id><title type="text">一个被我长期忽略的一个问题：验证控件与Button的OnClientClick事件</title><summary type="text">一个被我长期忽略的一个问题：验证控件与Button的OnClientClick事件</summary><published>2008-12-15T11:57:00Z</published><updated>2008-12-15T11:57:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2008/12/15/1355543.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2008/12/15/1355543.html"/></entry><entry><id>http://www.cnblogs.com/jiahaipeng/archive/2008/12/10/1351634.html</id><title type="text">远程数据自动导入的设计与实现</title><summary type="text">远程数据自动导入的设计与实现</summary><published>2008-12-10T02:33:00Z</published><updated>2008-12-10T02:33:00Z</updated><author><name>飞得更高</name><uri>http://www.cnblogs.com/jiahaipeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/jiahaipeng/archive/2008/12/10/1351634.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/jiahaipeng/archive/2008/12/10/1351634.html"/></entry></feed>
