#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <chrono>
#include <omp.h>
using namespace std;
using namespace std::chrono;
// Function generating a random array of given length
vector<int> randomArray(int length) {
vector<int> arr(length);
srand(time(0));
for (int i = 0; i < length; ++i) {
arr[i] = rand() % 1000; // Generating random numbers between 0 and 999
}
return arr;
}
// Bubble Sort in Serial mode
void bubbleSortSerial(vector<int>& 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]);
}
}
}
}
// Bubble Sort in Parallel mode
void bubbleSortParallel(vector<int>& arr) {
int n = arr.size();
#pragma omp parallel for
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]);
}
}
}
}
// Insertion Sort in Serial mode
void insertionSortSerial(vector<int>& arr) {
int n = arr.size();
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
--j;
}
arr[j + 1] = key;
}
}
// Insertion Sort in Parallel mode
void insertionSortParallel(vector<int>& arr) {
int n = arr.size();
#pragma omp parallel for
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
--j;
}
arr[j + 1] = key;
}
}
// Merge function in serial mode
void mergeSerial(vector<int>& arr, int left, int mid, int right) {
int n = mid - left + 1;
int m = right - mid;
vector<int> L(n), R(m);
for (int i = 0; i < n; ++i)
L[i] = arr[left + i];
for (int j = 0; j < m; ++j)
R[j] = arr[m + 1 + j];
int i = 0, j = 0, k = left;
while (i < n && j < m) {
if (L[i] <= R[j]) {
arr[k] = L[i];
++i;
}
else {
arr[k] = R[j];
++j;
}
++k;
}
while (i < n) {
arr[k] = L[i];
++i;
++k;
}
while (j < m) {
arr[k] = R[j];
++j;
++k;
}
}
// Merge sort in serial mode
void mergeSortSerial(vector<int>& arr, int left, int right) {
if (left >= right) return;
int mid = left + (right - left) / 2;
mergeSortSerial(arr, left, mid);
mergeSortSerial(arr, mid + 1, right);
mergeSerial(arr, left, mid, right);
}
// Merge function in Parallel
void mergeParallel(vector<int>& arr, int left, int mid, int right) {
int n = mid - left + 1;
int m = right - mid;
vector<int> L(n), R(m);
#pragma omp parallel for
for (int i = 0; i < n; ++i)
L[i] = arr[left + i];
#pragma omp parallel for
for (int j = 0; j < m; ++j)
R[j] = arr[mid + 1 + j];
int i = 0, j = 0, k = left;
while (i < n && j < m) {
if (L[i] <= R[j]) {
arr[k] = L[i];
++i;
}
else {
arr[k] = R[j];
++j;
}
++k;
}
while (i < n) {
arr[k] = L[i];
++i;
++k;
}
while (j < m) {
arr[k] = R[j];
++j;
++k;
}
}
// Merge sort in parallel mode
void mergeSortParallel(vector<int>& arr, int left, int right) {
if (left >= right) return;
int mid = left + (right - left) / 2;
#pragma omp parallel sections
{
#pragma omp section
mergeSortParallel(arr, left, mid);
#pragma omp section
mergeSortParallel(arr, mid + 1, right);
}
mergeParallel(arr, left, mid, right);
}
// Quick Sort partition in Serial
int partitionSerial(vector<int>& arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j <= high - 1; ++j) {
if (arr[j] < pivot) {
++i;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return (i + 1);
}
// Quick Sort in serial mode
void quickSortSerial(vector<int>& arr, int low, int high) {
if (low < high) {
int mid = partitionSerial(arr, low, high);
quickSortSerial(arr, low, mid - 1);
quickSortSerial(arr, mid + 1, high);
}
}
// Quick Sort partiton in Parallel
int partitionParallel(vector<int>& arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
#pragma omp parallel for
for (int j = low; j <= high - 1; ++j) {
if (arr[j] < pivot) {
#pragma omp critical
{
++i;
swap(arr[i], arr[j]);
}
}
}
swap(arr[i + 1], arr[high]);
return (i + 1);
}
// Quick Sort in Parallel mode
void quickSortParallel(vector<int>& arr, int low, int high) {
if (low < high) {
int mid = partitionParallel(arr, low, high);
#pragma omp parallel sections
{
#pragma omp section
quickSortParallel(arr, low, mid - 1);
#pragma omp section
quickSortParallel(arr, mid + 1, high);
}
}
}
int main() {
int length = 1000; // Length of the array
vector<int> array = randomArray(length);
// Bubble sort execution time in serial
auto serialBubbleStartTime = high_resolution_clock::now();
bubbleSortSerial(array);
auto serialBubbleEndTime = high_resolution_clock::now();
double serialBubbleTime = duration_cast<milliseconds>(serialBubbleEndTime - serialBubbleStartTime).count() / 1000.0;
// Insertion sort execution time in serial
auto serialInsertionStartTime = high_resolution_clock::now();
insertionSortSerial(array);
auto serialInsertionEndTime = high_resolution_clock::now();
double serialInsertionTime = duration_cast<milliseconds>(serialInsertionEndTime - serialInsertionStartTime).count() / 1000.0;
// Merge sort execution time in serial
auto serialMergeStartTime = high_resolution_clock::now();
mergeSortSerial(array, 0, length - 1);
auto serialMergeEndTime = high_resolution_clock::now();
double serialMergeTime = duration_cast<milliseconds>(serialMergeEndTime - serialMergeStartTime).count() / 1000.0;
// Quick sort execution time in serial
auto serialQuickStartTime = high_resolution_clock::now();
quickSortSerial(array, 0, length - 1);
auto serialQuickEndTime = high_resolution_clock::now();
double serialQuickTime = duration_cast<milliseconds>(serialQuickEndTime - serialQuickStartTime).count() / 1000.0;
cout << "Serial time for Bubble Sort: " << serialBubbleTime << " seconds." << endl;
cout << "Serial time for Insertion Sort: " << serialInsertionTime << " seconds." << endl;
cout << "Serial time for Merge Sort: " << serialMergeTime << " seconds." << endl;
cout << "Serial time for Quick Sort: " << serialQuickTime << " seconds." << endl;
// Parallel sorting using OpenMP
// Bubble sort execution time in parallel
auto parallelBubbleStartTime = high_resolution_clock::now();
bubbleSortParallel(array);
auto parallelBubbleEndTime = high_resolution_clock::now();
double parallelBubbleTime = duration_cast<milliseconds>(parallelBubbleEndTime - parallelBubbleStartTime).count() / 1000.0;
// Insertion sort execution time in parallel
auto parallelInsertionStartTime = high_resolution_clock::now();
insertionSortParallel(array);
auto parallelInsertionEndTime = high_resolution_clock::now();
double parallelInsertionTime = duration_cast<milliseconds>(parallelInsertionEndTime - parallelInsertionStartTime).count() / 1000.0;
// Merge sort execution time in parallel
auto parallelMergeStartTime = high_resolution_clock::now();
mergeSortParallel(array, 0, length - 1);
auto parallelMergeEndTime = high_resolution_clock::now();
double parallelMergeTime = duration_cast<milliseconds>(parallelMergeEndTime - parallelMergeStartTime).count() / 1000.0;
// Quick sort execution time in parallel
auto parallelQuickStartTime = high_resolution_clock::now();
quickSortParallel(array, 0, length - 1);
auto parallelQuickEndTime = high_resolution_clock::now();
double parallelQuickTime = duration_cast<milliseconds>(parallelQuickEndTime - parallelQuickStartTime).count() / 1000.0;
cout << "Parallel time for Bubble Sort: " << parallelBubbleTime << " seconds." << endl;
cout << "Parallel time for Insertion Sort: " << parallelInsertionTime << " seconds." << endl;
cout << "Parallel time for Merge Sort: " << parallelMergeTime << " seconds." << endl;
cout << "Parallel time for Quick Sort: " << parallelQuickTime << " seconds." << endl;
return 0;
}