1. Indice de pagina
  2. 1. Objetivos
  3. 2. Enunciado
  4. 2.1. Pistas
  5. 2.2. Funciones necesarias
  6. 3. Solución
  7. 3.1. Código
  8. 3.2. Salida

MergeSort

Objetivos

Enunciado

El MergeSort es un algoritmo de ordenación fácilmente paralelizable. Este algoritmo consiste en dividir el vector a ordenar en varias partes, estas partes se ordenan y, posteriormente, se mezclan entre ellas de forma ordenada. Dado que el proceso de mezcla es menos costoso que el proceso de ordenación obtenemos un algoritmo más eficiente. La forma paralela del algoritmo consiste en repartir una parte por proceso, realizando la ordenación de forma simultánea y luego la mezcla de dos en dos procesos.

Imagen Tutorial 6 MergeSort (Pulsar sobre la imagen para ver la animación)

Pistas

Ya hemos aprendido la manera de repartir un vector (MPI_Scatter).

El proceso de ordenación se hace paralelamente con todos los procesos, pero el de mezcla cada dos procesos uno se quedara sin trabajo.

Funciones necesarias

Solución

Código Descarga

#include <algorithm>
#include <vector>
#include "mpi.h" 
#include <iostream>
using namespace std;
 
int main(int argc, char *argv[]) 
{ 
    int rank, size, tama;
    vector<int> Global;//Vector a ordenar
    vector<int> *Local;//parte del vector
 
    MPI_Init(&argc, &argv);//iniciamos el entorno MPI
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);//obtenemos el identificador del proceso
    MPI_Comm_size(MPI_COMM_WORLD,&size);//obtenemos el numero de procesos
 
    if( size % 2 != 0 ){//El numero de procesos deberia debe ser par para aplicar este
algoritmo
    	cout<<"El numero de procesos debe ser par"<<endl;
    	MPI_Abort(MPI_COMM_WORLD,1);//abandonamos la ejecucion.
    }
 
    if(argc < 2){
    	if(rank == 0)
    		cout<< "No recibio parametro con el tamaño de vector, por defecto sera 1000"<<endl;
    	tama = 1000;
    }else{
    	tama = atoi(argv[1]);
    }
 
    if(rank == 0){//el proceso 0 genera un vector desordenado.
    	for(int i = 0; i < tama;++i){
    		Global.push_back(rand()%1000);
    	}
    }
    Local = new vector<int>(tama/size);// reservamos espacio para el vector local a cada
proceso.
 
    //Repartimos el vector entre todos los procesos.
 
MPI_Scatter(&Global[0],tama/size,MPI_INT,&((*Local)[0]),tama/size,MPI_INT,0,MPI_COMM_WORLD);
 
    //Cada proceso ordena su parte.
    sort(Local->begin(),Local->end());
 
    vector<int> *ordenado;
    MPI_Status status;
    int paso = 1;
 
    //Ahora comienza el proceso de mezcla.
    while(paso<size)
    {
	// Cada pareja de procesos
        if(rank%(2*paso)==0) // El izquierdo recibe el vector y mezcla
        {
            if(rank+paso<size)// los procesos sin pareja esperan.
            {
            	vector<int> localVecino(Local->size());
            	ordenado = new vector<int>(Local->size()*2);
 
 
MPI_Recv(&localVecino[0],localVecino.size(),MPI_INT,rank+paso,0,MPI_COMM_WORLD,&status);
                merge(
Local->begin(),Local->end(),localVecino.begin(),localVecino.end(),ordenado->begin() );
 
                delete Local;
                Local = ordenado;
                ordenado = NULL;
            }
        }
        else // El derecho envia su vector ordenado y termina
        {
            int vecino = rank-paso;
            MPI_Send(&((*Local)[0]),Local->size(),MPI_INT,vecino,0,MPI_COMM_WORLD);
            break;//Sale del bucle
        }
        paso = paso*2;// el paso se duplica ya que el numero de procesos se reduce a la
mita.
    }
 
    if(rank == 0){
    	cout<<endl<<"[";
    	for(unsigned int i = 0; i<Local->size();++i){
    		cout<< (*Local)[i]<<" , ";
    	}
    	cout<<"]"<<endl;
    }
 
    MPI_Finalize();
    return 0; 
}

Salida

> mpiCC mergesort.cpp -o mergesort
> mpirun -np 8 mergesort 100

[11 , 12 , 22 , 27 , 42 , 43 , 58 , 59 , 60 , 67 , 69 , 84 , 87 , 91 , 123 ,
124 , 135 , 167 , 170 , 172 , 178 , 198 , 211 , 229 , 276 , 281 , 305 , 313 ,
315 , 324 , 327 , 335 , 336 , 362 , 364 , 367 , 368 , 368 , 370 , 373 , 383 ,
386 , 393 , 399 , 403 , 413 , 421 , 421 , 426 , 429 , 434 , 456 , 492 , 505 ,
526 , 530 , 537 , 540 , 545 , 567 , 582 , 584 , 649 , 651 , 676 , 690 , 729 ,
736 , 739 , 750 , 754 , 763 , 777 , 782 , 784 , 788 , 793 , 802 , 808 , 814 ,
846 , 857 , 862 , 862 , 873 , 886 , 895 , 915 , 919 , 925 , 926 , 929 , 932 ,
956 , 980 , 996 , ]
Creado por: Daniel Guerrero Martínez y Sergio Rodríguez Lumley 2010

Valid HTML 4.01 Transitional