堆排是串行排序中最适合并行化的排序之一
1/分为主线程和从线程
2/主线程分发数据,使用大小与从线程个数相同的堆作为私有堆,进行最后整理用
3/从线程维护一个堆,每次返回给主线程堆顶元素
4/主线程 提取堆顶元素 通知相应从线程提交新的堆顶元素
5/主从线程并行进行重建堆(heapify)的动作
#include "mpi.h" #include <stdio.h> #include <stdlib.h> #define ROOT 0 #define TAG 0 #define NEXT 1 #define END -1 typedef struct node { int v; int r; } Node; static inline int left(int i) { return i*2+1; } static inline int right(int i) { return left(i)+1; } void defineIntVector(MPI_Datatype* type,int length) { MPI_Type_vector(length,1,1,MPI_INT,type); MPI_Type_commit(type); } //for slaves void heapifyI(int *a,int root,int size) { int l=left(root); int r=right(root); int m=root; if(l<size&&a[l]<a[m]) { m=l; } if(r<size&&a[r]<a[m]) { m=r; } if(m!=root) { int t=a[root]; a[root]=a[m]; a[m]=t; heapifyI(a,m,size); } } void buildHeapI(int *a,int size) { for(int i=(size-1)/2;i>=0;--i) { heapifyI(a,i,size); } } //for root void heapifyN(Node *a,int root,int size) { int l=left(root); int r=right(root); int m=root; if(l<size&&a[l].v<a[m].v) { m=l; } if(r<size&&a[r].v<a[m].v) { m=r; } if(m!=root) { Node t=a[root]; a[root]=a[m]; a[m]=t; heapifyN(a,m,size); } } void buildHeapN(Node *a,int size) { for(int i=(size-1)/2;i>=0;--i) { heapifyN(a,i,size); } } int main(int argc,char *argv[]) { int self,size; int part;//threshold MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&self); MPI_Comm_size(MPI_COMM_WORLD,&size); MPI_Status status; MPI_Datatype MPI_VEC; if(ROOT==self) { //all data int values[]={1,5,3,8,4,2,9,6,7,54,34,6,13,63,32,14,53,21,65,33,24,213,23,14,21,65,32}; int length=27; //for each process part=length/(size-1); MPI_Bcast(&part,1,MPI_INT,ROOT,MPI_COMM_WORLD); defineIntVector(&MPI_VEC,part); //heap for min value from each process Node *nodes=(Node*)malloc((size-1)*sizeof(Node)); for(int i=0;i<size-1;++i) { nodes[i].r=i+1; } //send out all the data for(int i=1;i<size;++i) { MPI_Ssend(&values[(i-1)*part],1,MPI_VEC,i,TAG,MPI_COMM_WORLD); } for(int i=1;i<size;++i) { MPI_Recv(&(nodes[i-1].v),1,MPI_INT,i,TAG,MPI_COMM_WORLD,&status); } //end flag part=size-1; //build a heap representing process buildHeapN(nodes,part); int p=0; while(part>0) { values[p++]=nodes[0].v; //similar to the message passing system of select sort MPI_Ssend(&p,1,MPI_INT,nodes[0].r,NEXT,MPI_COMM_WORLD); MPI_Recv(&(nodes[0].v),1,MPI_INT,nodes[0].r,TAG,MPI_COMM_WORLD,&status); if(END==nodes[0].v) { nodes[0]=nodes[--part]; } heapifyN(nodes,0,part); } for(int i=0;i<length;++i) printf("%d ",values[i]); free(nodes); } else { MPI_Bcast(&part,1,MPI_INT,ROOT,MPI_COMM_WORLD); defineIntVector(&MPI_VEC,part); int *values=(int*)malloc(part*sizeof(int)); MPI_Recv(values,1,MPI_VEC,ROOT,TAG,MPI_COMM_WORLD,&status); buildHeapI(values,part); //send the smallest MPI_Ssend(&values[0],1,MPI_INT,ROOT,TAG,MPI_COMM_WORLD); //pop out one values[0]=values[--part]; //rebuild heap heapifyI(values,0,part); while(part>0) { MPI_Recv(&values[part],1,MPI_INT,ROOT,NEXT,MPI_COMM_WORLD,&status); MPI_Ssend(&values[0],1,MPI_INT,ROOT,TAG,MPI_COMM_WORLD); values[0]=values[--part]; heapifyI(values,0,part); } MPI_Recv(&values[part],1,MPI_INT,ROOT,NEXT,MPI_COMM_WORLD,&status); values[0]=END; MPI_Ssend(&values[0],1,MPI_INT,ROOT,TAG,MPI_COMM_WORLD); free(values); } MPI_Finalize(); return 0; }