Implementation of Quick sort using MPI, OMP and Posix thread - GeeksforGeeks

01 Nov, 2021
QuickSort is a Divide and Conquer Algorithm. It picks an element as a pivot and partitions the array around the picked pivot. There are many ways of choosing the pivot elements. They are:
Always pick the first element as a pivot.
Always pick the last element as the pivot (implemented below)
Pick a random element as a pivot.
Pick median as a pivot.      
MPI: MPI stands for Message Passing Interface. Here the message is data. MPI allows data to be passed between processes in a distributed memory environment. In C, “mpi.h” is a header file that includes all data structures, routines, and constants of MPI. Using “mpi.h” parallelized the quick sort algorithm.  Below is the C program to implement quicksort using MPI:
C
// C program to implement the Quick Sort// Algorithm using MPI#include <mpi.h>#include <stdio.h>#include <stdlib.h>#include <time.h>#include <unistd.h>using namespace std; // Function to swap two numbersvoid swap(int* arr, int i, int j){    int t = arr[i];    arr[i] = arr[j];    arr[j] = t;} // Function that performs the Quick Sort// for an array arr[] starting from the// index start and ending at index endvoid quicksort(int* arr, int start, int end){    int pivot, index;     // Base Case    if (end <= 1)        return;     // Pick pivot and swap with first    // element Pivot is middle element    pivot = arr[start + end / 2];    swap(arr, start, start + end / 2);     // Partitioning Steps    index = start;     // Iterate over the range [start, end]    for (int i = start + 1; i < start + end; i++) {         // Swap if the element is less        // than the pivot element        if (arr[i] < pivot) {            index++;            swap(arr, i, index);        }    }     // Swap the pivot into place    swap(arr, start, index);     // Recursive Call for sorting    // of quick sort function    quicksort(arr, start, index - start);    quicksort(arr, index + 1, start + end - index - 1);} // Function that merges the two arraysint* merge(int* arr1, int n1, int* arr2, int n2){    int* result = (int*)malloc((n1 + n2) * sizeof(int));    int i = 0;    int j = 0;    int k;     for (k = 0; k < n1 + n2; k++) {        if (i >= n1) {            result[k] = arr2[j];            j++;        }        else if (j >= n2) {            result[k] = arr1[i];            i++;        }         // Indices in bounds as i < n1        // && j < n2        else if (arr1[i] < arr2[j]) {            result[k] = arr1[i];            i++;        }         // v2[j] <= v1[i]        else {            result[k] = arr2[j];            j++;        }    }    return result;} // Driver Codeint main(int argc, char* argv[]){    int number_of_elements;    int* data = NULL;    int chunk_size, own_chunk_size;    int* chunk;    FILE* file = NULL;    double time_taken;    MPI_Status status;     if (argc != 3) {        printf("Desired number of arguments are not their "               "in argv....\n");        printf("2 files required first one input and "               "second one output....\n");        exit(-1);    }     int number_of_process, rank_of_process;    int rc = MPI_Init(&argc, &argv);     if (rc != MPI_SUCCESS) {        printf("Error in creating MPI "               "program.\n "               "Terminating......\n");        MPI_Abort(MPI_COMM_WORLD, rc);    }     MPI_Comm_size(MPI_COMM_WORLD, &number_of_process);    MPI_Comm_rank(MPI_COMM_WORLD, &rank_of_process);     if (rank_of_process == 0) {        // Opening the file        file = fopen(argv[1], "r");         // Printing Error message if any        if (file == NULL) {            printf("Error in opening file\n");            exit(-1);        }         // Reading number of Elements in file ...        // First Value in file is number of Elements        printf(            "Reading number of Elements From file ....\n");        fscanf(file, "%d", &number_of_elements);        printf("Number of Elements in the file is %d \n",               number_of_elements);         // Computing chunk size    chunk_size = (number_of_elements %                  number_of_process == 0) ?                  (number_of_elements /                   number_of_process) :                  (number_of_elements /                  (number_of_process - 1);     data = (int *)malloc(number_of_process *                         chunk_size *                         sizeof(int));         // Reading the rest elements in which    // operation is being performed    printf("Reading the array from the file.......\n");    for(int i = 0; i < number_of_elements; i++)    {            fscanf(file, "%d", &data[i]);    }     // Padding data with zero    for(int i = number_of_elements;            i < number_of_process *                chunk_size; i++)    {            data[i] = 0;    }     // Printing the array read from file      printf("Elements in the array is : \n");      for(int i = 0; i < number_of_elements; i++)      {            printf("%d  ", data[i]);      }       printf("\n");       fclose(file);      file = NULL;    }     // Blocks all process until reach this point    MPI_Barrier(MPI_COMM_WORLD);     // Starts Timer    time_taken -= MPI_Wtime();     // BroadCast the Size to all the    // process from root process    MPI_Bcast(&number_of_elements, 1, MPI_INT, 0,              MPI_COMM_WORLD);     // Computing chunk size  chunk_size= (number_of_elements %               number_of_process == 0) ?              (number_of_elements /               number_of_process) :              (number_of_elements /              (number_of_process - 1);   // Calculating total size of chunk  // according to bits  chunk = (int *)malloc(chunk_size *                        sizeof(int));   // Scatter the chuck size data to all process  MPI_Scatter(data, chunk_size, MPI_INT, chunk,              chunk_size, MPI_INT, 0, MPI_COMM_WORLD);  free(data);  data = NULL;   // Compute size of own chunk and               // then sort them  // using quick sort   own_chunk_size = (number_of_elements >=                    chunk_size*(rank_of_process + 1)) ?                    chunk_size : (number_of_elements -                                  chunk_size*rank_of_process);   // Sorting array with quick sort for every  // chunk as called by process  quicksort(chunk, 0, own_chunk_size);   for(int step = 1; step < number_of_process; step = 2 * step)  {        if (rank_of_process % (2 * step) != 0) {            MPI_Send(chunk, own_chunk_size, MPI_INT,                     rank_of_process - step, 0,                     MPI_COMM_WORLD);            break;        }         if (rank_of_process + step < number_of_process) {            int received_chunk_size                = (number_of_elements                   >= chunk_size                          * (rank_of_process + 2 * step))                      ? (chunk_size * step)                      : (number_of_elements                         - chunk_size                               * (rank_of_process + step));            int* chunk_received;            chunk_received = (int*)malloc(                received_chunk_size * sizeof(int));            MPI_Recv(chunk_received, received_chunk_size,                     MPI_INT, rank_of_process + step, 0,                     MPI_COMM_WORLD, &status);             data = merge(chunk, own_chunk_size,                         chunk_received,                         received_chunk_size);             free(chunk);            free(chunk_received);            chunk = data;            own_chunk_size                = own_chunk_size + received_chunk_size;        }  }   // Stop the timer  time_taken += MPI_Wtime();   // Opening the other file as taken form input  // and writing it to the file and giving it  // as the output  if(rank_of_process == 0)  {        // Opening the file        file = fopen(argv[2], "w");         if (file == NULL) {            printf("Error in opening file... \n");            exit(-1);        }         // Printing total number of elements        // in the file        fprintf(            file,            "Total number of Elements in the array : %d\n",            own_chunk_size);         // Printing the value of array in the file        for (int i = 0; i < own_chunk_size; i++) {            fprintf(file, "%d  ", chunk[i]);        }         // Closing the file        fclose(file);         printf("\n\n\n\nResult printed in output.txt file "               "and shown below: \n");         // For Printing in the terminal        printf("Total number of Elements given as input : "               "%d\n",               number_of_elements);        printf("Sorted array is: \n");         for (int i = 0; i < number_of_elements; i++) {            printf("%d  ", chunk[i]);        }         printf(            "\n\nQuicksort %d ints on %d procs: %f secs\n",            number_of_elements, number_of_process,            time_taken);  }   MPI_Finalize();  return 0;}
Output:
OMP: OMP is Open Multi-Processing. It’s an Application Program Interface (API) that may be used to explicitly direct multi-threaded, shared memory parallelism. In C/ C++, “omp.h” is a header file that includes all the related directives related to OMP. Using “omp.h” parallelized quick sort. Below is the C++ program to implement the above concept:
C++
// C++ program to implement the Quick Sort// using OMI#include <bits/stdc++.h>#include <omp.h>using namespace std; // Function to swap two numbers a and bvoid swap(int* a, int* b){    int t = *a;    *a = *b;    *b = t;} // Function to perform the partitioning// of array arr[]int partition(int arr[], int start, int end){    // Declaration    int pivot = arr[end];    int i = (start - 1);     // Rearranging the array    for (int j = start; j <= end - 1; j++) {        if (arr[j] < pivot) {            i++;            swap(&arr[i], &arr[j]);        }    }    swap(&arr[i + 1], &arr[end]);     // Returning the respective index    return (i + 1);} // Function to perform QuickSort Algorithm// using openmpvoid quicksort(int arr[], int start, int end){    // Declaration    int index;     if (start < end) {         // Getting the index of pivot        // by partitioning        index = partition(arr, start, end); // Parallel sections#pragma omp parallel sections        {#pragma omp section            {                // Evaluating the left half                quicksort(arr, start, index - 1);            }#pragma omp section            {                // Evaluating the right half                quicksort(arr, index + 1, end);            }        }    }} // Driver Codeint main(){    // Declaration    int N;     // Taking input the number of    // elements we wants    cout << "Enter the number of elements"         << " you want to Enter\n";    cin >> N;     // Declaration of array    int arr[N];     cout << "Enter the array: \n";     // Taking input that array    for (int i = 0; i < N; i++) {        cin >> arr[i];    }     // Calling quicksort having parallel    // code implementation    quicksort(arr, 0, N - 1);     // Printing the sorted array    cout << "Array after Sorting is: \n";     for (int i = 0; i < N; i++) {        cout << arr[i] << " ";    }     return 0;}
Output: 
POSIX Threads: The POSIX thread libraries are a C/C++ thread API based on standards. It enables the creation of a new concurrent process flow. It works well on multi-processor or multi-core systems, where the process flow may be scheduled to execute on another processor, increasing speed through parallel or distributed processing. Below is the C++ program to implement quicksort using POSIX threads: 
C++14
// C++ program to implement the Quick Sort// using POSIX Thread#include <bits/stdc++.h>#include <pthread.h>using namespace std; // Structurestruct data_set {    int start_index;    int end_index;    int* data;}; // Function to perform swap operationsvoid swap(int* a, int* b){    int t = *a;    *a = *b;    *b = t;} // Partition function for making// partition in arrayint partition(int arr[], int left_index,              int right_index){    // Declaration and initialization    // choosing pivot element form which    // we make partition     // Here pivot is last element of    // the array    int pivot = arr[right_index];    int i = left_index - 1;     // Making array as per requirement    // arranging element smaller than    // pivot on left side and larger    // then pivot on right side    for (int j = left_index;         j <= right_index - 1; j++) {         if (arr[j] < pivot) {            i++;            swap(&arr[i], &arr[j]);        }    }     swap(&arr[i + 1], &arr[right_index]);     // Returning the partition index    return i + 1;} // Quicksort Function for sorting// arrayvoid* quick_sort(void* data){    // Retrieving back the data sent    // from thread    struct data_set* info = (struct data_set*)data;     // Declaration of left index    int left_index, right_index, index;     // Initialization of left and    // right index    left_index = info->start_index;    right_index = info->end_index;     // Recursive call of quick_sort    // function    if (left_index < right_index) {         // Declaration of pthread and        // pthread attribute type object        pthread_attr_t attr;        pthread_t first_thread;        pthread_t second_thread;         // Making two pointers of type        // data_set for making again        // call form thread        struct data_set* info1 = new data_set;        struct data_set* info2 = new data_set;         // Their initialization        info1->data = info->data;        info2->data = info->data;         // Initialize of pthread attribute        pthread_attr_init(&attr);         // For setting the set detach        // state of attribute        pthread_attr_setdetachstate(            &attr, PTHREAD_CREATE_JOINABLE);         // Partition the array for any        // recursive call        index = partition(info->data,                          left_index,                          right_index);         info1->start_index = left_index;        info1->end_index = index - 1;         // Create pthread type object and        // printing the error if any        if (pthread_create(&first_thread,                           &attr, quick_sort,                           info1)) {            cout << "Error in creating thread "                 << endl;             // Exiting in case of not            // creation of thread            exit(-1);        }         info2->start_index = index + 1;        info2->end_index = right_index;         // Creating pthread type object        // and print the error        if (pthread_create(&second_thread,                           &attr, quick_sort,                           info2)) {            cout << "Error in creating thread "                 << endl;             // Exiting in case of not            // creation of thread            exit(-1);        }         // Joining the threads        pthread_join(first_thread, NULL);        pthread_join(second_thread, NULL);    }     return NULL;} // Driver Codeint main(){    // Declaration of Number of threads    int N;     struct data_set* info = new data_set;     // Taking number of elements as input    cout << "Enter number of elements"         << " in the array: \n";    cin >> N;     // Declaration of array    int A[N];     // Initialization of array    cout << "Enter the array: " << endl;    for (int i = 0; i < N; i++) {        cin >> A[i];    }     // Initialize of structure of    // data_set type    info->data = A;    info->start_index = 0;    info->end_index = N - 1;     // Declaration of pthread object    pthread_t thread_id;     // Creating and pthread object and    // printing the array of any    if (pthread_create(&thread_id, NULL,                       quick_sort,                       info)) {        cout << "Error in creating thread"             << endl;         // Exit in case of error        exit(-1);    }     // Joining the pthread object    int r1 = pthread_join(thread_id, NULL);     // Printing the array if any in case    // of joining    if (r1) {        cout << "Error in Joinging thread"             << endl;         // Exiting in case of error        exit(-1);    }     // Printing the array after sorting    cout << "Sorted Array is: " << endl;     for (int i = 0; i < N; i++) {        cout << A[i] << " ";    }    cout << endl;     // Exiting from pthread programming    pthread_exit(NULL);     return 0;}
Output:
 
kapoorsagar226
gabaa406
anikakapoor
sagar0719kumar
adnanirshad158
ruhelaa48
sweetyty
prachisoda1234
Quick Sort
C Programs
C++ Programs
Mathematical
Operating Systems
Sorting
Operating Systems
Mathematical
Sorting
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
C Program to read contents of Whole File
Producer Consumer Problem in C
Exit codes in C/C++ with Examples
C program to find the length of a string
Handling multiple clients on server with multithreading using Socket Programming in C/C++
C++ Program for QuickSort
Sorting a Map by value in C++ STL
Shallow Copy and Deep Copy in C++
delete keyword in C++
C++ program for hashing with chaining