diff --git a/Codes/Code-2.cpp b/Codes/Code-2.cpp new file mode 100644 index 0000000..5fc0069 --- /dev/null +++ b/Codes/Code-2.cpp @@ -0,0 +1,196 @@ +// Code-2 (Parallel Bubble Sort and Merge Sort) + +/* + * THIS CODE HAS BEEN TESTED AND IS FULLY OPERATIONAL. + * + * Problem Statement: + * Write a program to implement Parallel Bubble Sort and Merge sort using OpenMP. + * Use existing algorithms and measure the performance of sequential and parallel algorithms. + * + * Code from HighPerformanceComputing (SPPU - Final Year - Computer Engineering - Content) + * repository on KSKA Git: https://git.kska.io/sppu-be-comp-content/HighPerformanceComputing + **/ + +/* + * EXECUTION INSTRUCTIONS (Debian-based distributions): + * + * i) Install g++ with OpenMP support: + * sudo apt update + * sudo apt install g++ + * + * ii) Compile: + * g++ -fopenmp Code-2.cpp -o Code-2 + * + * iii) Execute: + * ./Code-2 + **/ + +// BEGINNING OF CODE +#include +#include +#include +#include + +using namespace std; + +void printArray(const vector& arr) { + for (int num : arr) + cout << num << " "; + cout << endl; +} + +// Bubble Sort + +// Sequential bubble sort. +// Sorts the array using bubble sort by repeatedly swapping adjacent elements. +void sequentialBubbleSort(vector& arr) { + int n = arr.size(); + for (int i = 0; i < n - 1; i++) { + for (int j = 0; j < n - i - 1; j++) { + if (arr[j] > arr[j + 1]) + swap(arr[j], arr[j + 1]); + } + } +} + +// Parallel bubble sort using odd-even transposition. +// Standard bubble sort cannot be parallelized directly: thread on index j +// and thread on index j+1 would both touch arr[j+1] simultaneously (data race). +// Odd-even transposition alternates between two phases each pass: +// Phase 0 (even): compare pairs (0,1), (2,3), (4,5), ... +// Phase 1 (odd): compare pairs (1,2), (3,4), (5,6), ... +// Within each phase every pair is independent, so threads never share elements. +void parallelBubbleSort(vector& arr) { + int n = arr.size(); + for (int i = 0; i < n; i++) { + // i % 2 selects even phase (0) or odd phase (1). + // The starting index of the first pair in each phase matches i % 2. + #pragma omp parallel for + for (int j = i % 2; j < n - 1; j += 2) { + if (arr[j] > arr[j + 1]) + swap(arr[j], arr[j + 1]); + } + } +} + +// Merge Sort + +// Merges two sorted halves arr[left..mid] and arr[mid+1..right] in place. +void merge(vector& arr, int left, int mid, int right) { + int n1 = mid - left + 1; + int n2 = right - mid; + + vector L(n1), R(n2); + for (int i = 0; i < n1; i++) L[i] = arr[left + i]; + for (int i = 0; i < n2; i++) R[i] = arr[mid + 1 + i]; + + int i = 0, j = 0, k = left; + while (i < n1 && j < n2) + arr[k++] = (L[i] <= R[j]) ? L[i++] : R[j++]; + + while (i < n1) arr[k++] = L[i++]; + while (j < n2) arr[k++] = R[j++]; +} + +void sequentialMergeSort(vector& arr, int left, int right) { + if (left >= right) return; + int mid = left + (right - left) / 2; + sequentialMergeSort(arr, left, mid); + sequentialMergeSort(arr, mid + 1, right); + merge(arr, left, mid, right); +} + +// Parallel merge sort using OpenMP tasks. +// "#pragma omp parallel sections" inside a recursive function would spawn a +// new thread team at every level of recursion, hundreds of thousands of teams +// for a large array, causing enormous overhead and likely a crash. +// Tasks are lighter: the runtime schedules them across an existing thread pool. +// The depth cutoff switches to sequential below a threshold to avoid spawning +// tasks so small that the overhead exceeds the work itself. +void parallelMergeSortHelper(vector& arr, int left, int right, int depth) { + if (left >= right) return; + int mid = left + (right - left) / 2; + + if (depth <= 0) { + // Below the cutoff the subarray is small enough that sequential is faster. + sequentialMergeSort(arr, left, mid); + sequentialMergeSort(arr, mid + 1, right); + } else { + #pragma omp task + parallelMergeSortHelper(arr, left, mid, depth - 1); + + #pragma omp task + parallelMergeSortHelper(arr, mid + 1, right, depth - 1); + + // Wait for both tasks to finish before merging. + #pragma omp taskwait + } + + merge(arr, left, mid, right); +} + +void parallelMergeSort(vector& arr, int left, int right) { + // The single directive creates one thread team for the entire sort. + // All recursive tasks share this pool instead of creating new teams. + #pragma omp parallel + { + // single ensures only one thread kicks off the root task; + // the rest wait and pick up the child tasks as they are created. + #pragma omp single + parallelMergeSortHelper(arr, left, right, 4); // depth 4 → up to 16 parallel tasks + } +} + +// Main function + +int main() { + int n = 10000; // Adjust this to specify the number of elements. + vector arr(n); + + for (int i = 0; i < n; i++) + arr[i] = rand() % 10000; + + double start, end; + + // --- Sequential Bubble Sort --- + vector seqArr = arr; + start = omp_get_wtime(); + sequentialBubbleSort(seqArr); + end = omp_get_wtime(); + cout << "Sequential Bubble Sort time: " << (end - start) << " seconds" << endl; + + // --- Parallel Bubble Sort --- + vector parArr = arr; + start = omp_get_wtime(); + parallelBubbleSort(parArr); + end = omp_get_wtime(); + cout << "Parallel Bubble Sort time: " << (end - start) << " seconds" << endl; + + // --- Sequential Merge Sort --- + seqArr = arr; + start = omp_get_wtime(); + sequentialMergeSort(seqArr, 0, n - 1); + end = omp_get_wtime(); + cout << "Sequential Merge Sort time: " << (end - start) << " seconds" << endl; + + // --- Parallel Merge Sort --- + parArr = arr; + start = omp_get_wtime(); + parallelMergeSort(parArr, 0, n - 1); + end = omp_get_wtime(); + cout << "Parallel Merge Sort time: " << (end - start) << " seconds" << endl; + + return 0; +} +// END OF CODE + +/* +EXAMPLE OUTPUT (when n=10000): + +$ ./Code-2 +Sequential Bubble Sort time: 0.955806 seconds +Parallel Bubble Sort time: 0.296248 seconds +Sequential Merge Sort time: 0.0114291 seconds +Parallel Merge Sort time: 0.00343183 seconds +*/ +