Quick Sort using Multi-threading

QuickSort is a popular sorting technique based on divide and conquer algorithm. In this technique, an element is chosen as a pivot and the array is partitioned around it. The target of partition is, given an array and an element x of the array as a pivot, put x at its correct position in a sorted array and put all smaller elements (smaller than x) before x, and put all greater elements (greater than x) after x.
Multi-threading allows concurrent execution of two or more parts of a program for maximum utilization of CPU. Each part of such program is called a thread. So, threads are light-weight processes within a process.
Examples: 
 
Input: arr[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
Output: 1 2 3 4 5 6 7 8 9 10
Input: arr[] = {54, 64, 95, 82, 12, 32, 63}
Output: 12 32 54 63 64 82 95
Approach: The main idea of the approach is: 
 
- The main thread calls the quicksort method.
 - The method partitions the array and checks for the number of current threads.
 - New threads is called for next step using the same parallel method.
 - Use the single normal quicksort method.
 
Below is the program uses ForkJoinPool thread pool to keep number of thread same as the number of CPUs and reuse the threads:
 
C++
#include <iostream>#include <vector>#include <algorithm>#include <cstdlib>#include <ctime>#include <omp.h>using namespace std;class QuickSortMultiThreading {public:    QuickSortMultiThreading(int start, int end, vector<int>& arr)        : start_(start), end_(end), arr_(arr) {}         // Finding random pivoted and partition    // array on a pivot.    // There are many different    // partitioning algorithms.    int partition(int start, int end, vector<int>& arr) {        int i = start;        int j = end;        // Decide random pivot        int pivoted = rand() % (j - i + 1) + i;        // Swap the pivoted with end        // element of array        int t = arr[j];        arr[j] = arr[pivoted];        arr[pivoted] = t;        j--;        // Start partitioning        while (i <= j) {            if (arr[i] <= arr[end]) {                i++;                continue;            }            if (arr[j] >= arr[end]) {                j--;                continue;            }            t = arr[j];            arr[j] = arr[i];            arr[i] = t;            j--;            i++;        }        // Swap pivoted to its        // correct position        t = arr[j + 1];        arr[j + 1] = arr[end];        arr[end] = t;        return j + 1;    }    // Function to implement    // QuickSort method    void operator() () {        // Base case        if (start_ >= end_) {            return;        }        // Find partition        int p = partition(start_, end_, arr_);        // Divide array        QuickSortMultiThreading left(start_, p - 1, arr_);        QuickSortMultiThreading right(p + 1, end_, arr_);        // Left subproblem as separate thread        #pragma omp parallel sections        {            #pragma omp section            {                left();            }            #pragma omp section            {                right();            }        }    }private:    int start_;    int end_;    vector<int>& arr_;};int main() {    int n = 7;    vector<int> arr = {54, 64, 95, 82, 12, 32, 63};    srand(time(NULL));    QuickSortMultiThreading(0, n - 1, arr)();    for (int i = 0; i < n; i++) {        // Print sorted elements        cout << arr[i] << " ";    }    cout << endl;    return 0;} | 
Java
// Java program for the above approachimport java.io.*;import java.util.Random;import java.util.concurrent.ForkJoinPool;import java.util.concurrent.RecursiveTask;public class QuickSortMutliThreading    extends RecursiveTask<Integer> {    int start, end;    int[] arr;    /**     * Finding random pivoted and partition     * array on a pivot.     * There are many different     * partitioning algorithms.     * @param start     * @param end     * @param arr     * @return     */    private int partition(int start, int end,                        int[] arr)    {        int i = start, j = end;        // Decide random pivot        int pivoted = new Random()                         .nextInt(j - i)                     + i;        // Swap the pivoted with end        // element of array;        int t = arr[j];        arr[j] = arr[pivote];        arr[pivote] = t;        j--;        // Start partitioning        while (i <= j) {            if (arr[i] <= arr[end]) {                i++;                continue;            }            if (arr[j] >= arr[end]) {                j--;                continue;            }            t = arr[j];            arr[j] = arr[i];            arr[i] = t;            j--;            i++;        }        // Swap pivoted to its        // correct position        t = arr[j + 1];        arr[j + 1] = arr[end];        arr[end] = t;        return j + 1;    }    // Function to implement    // QuickSort method    public QuickSortMutliThreading(int start,                                   int end,                                   int[] arr)    {        this.arr = arr;        this.start = start;        this.end = end;    }    @Override    protected Integer compute()    {        // Base case        if (start >= end)            return null;        // Find partition        int p = partition(start, end, arr);        // Divide array        QuickSortMutliThreading left            = new QuickSortMutliThreading(start,                                          p - 1,                                          arr);        QuickSortMutliThreading right            = new QuickSortMutliThreading(p + 1,                                          end,                                          arr);        // Left subproblem as separate thread        left.fork();        right.compute();        // Wait until left thread complete        left.join();        // We don't want anything as return        return null;    }    // Driver Code    public static void main(String args[])    {        int n = 7;        int[] arr = { 54, 64, 95, 82, 12, 32, 63 };        // Forkjoin ThreadPool to keep        // thread creation as per resources        ForkJoinPool pool            = ForkJoinPool.commonPool();        // Start the first thread in fork        // join pool for range 0, n-1        pool.invoke(            new QuickSortMutliThreading(                0, n - 1, arr));        // Print shorted elements        for (int i = 0; i < n; i++)            System.out.print(arr[i] + " ");    }} | 
Python3
# Python3 program for the above approachimport randomfrom concurrent.futures import ThreadPoolExecutorclass QuickSortMultiThreading:    def __init__(self, start, end, arr):        self.start = start        self.end = end        self.arr = arr     # Finding random pivoted and partition     # array on a pivot.     # There are many different     # partitioning algorithms.     # @param start     # @param end     # @param arr     # @return    def partition(self, start, end, arr):        i = start        j = end                 # Decide random pivot        pivoted = random.randint(i, j)                 # Swap the pivoted with end        # element of array        t = arr[j]        arr[j] = arr[pivoted]        arr[pivoted] = t        j -= 1                 # Start partitioning        while i <= j:            if arr[i] <= arr[end]:                i += 1                continue            if arr[j] >= arr[end]:                j -= 1                continue            t = arr[j]            arr[j] = arr[i]            arr[i] = t            j -= 1            i += 1                     # Swap pivoted to its        # correct position        t = arr[j + 1]        arr[j + 1] = arr[end]        arr[end] = t        return j + 1    # Function to implement    # QuickSort method    def __call__(self):               # Base case        if self.start >= self.end:            return                   # Find partition        p = self.partition(self.start, self.end, self.arr)                 # Divide array        left = QuickSortMultiThreading(self.start, p - 1, self.arr)        right = QuickSortMultiThreading(p + 1, self.end, self.arr)                 # Left subproblem as separate thread        with ThreadPoolExecutor(max_workers=2) as executor:            futures = [executor.submit(left), executor.submit(right)]            for future in futures:                future.result()# Driver Codeif __name__ == '__main__':    n = 7    arr = [54, 64, 95, 82, 12, 32, 63]    QuickSortMultiThreading(0, n - 1, arr)()    for i in range(n):                # Print shorted elements        print(arr[i], end=' ') | 
C#
// C# program for the above approachusing System;using System.Collections.Generic;using System.Threading.Tasks;class QuickSortMultiThreading {    private int start;    private int end;    private int[] arr;    private Random random;    public QuickSortMultiThreading(int start, int end, int[] arr) {        this.start = start;        this.end = end;        this.arr = arr;        random = new Random();    }          // Finding random pivoted and partition     // array on a pivot.     // There are many different     // partitioning algorithms.     // @param start     // @param end     // @param arr     // @return    private int Partition(int start, int end, int[] arr) {        int i = start;        int j = end;                 // Decide random pivot        int pivoted = random.Next(i, j + 1);                 // Swap the pivoted with end        // element of array        int t = arr[j];        arr[j] = arr[pivoted];        arr[pivoted] = t;        j -= 1;        // Start partitioning        while (i <= j) {            if (arr[i] <= arr[end]) {                i += 1;                continue;            }            if (arr[j] >= arr[end]) {                j -= 1;                continue;            }            t = arr[j];            arr[j] = arr[i];            arr[i] = t;            j -= 1;            i += 1;        }                 // Swap pivoted to its        // correct position        t = arr[j + 1];        arr[j + 1] = arr[end];        arr[end] = t;        return j + 1;    }         // Function to implement    // QuickSort method    public void Sort() {        if (start >= end) {            return;        }        int p = Partition(start, end, arr);        QuickSortMultiThreading left = new QuickSortMultiThreading(start, p - 1, arr);        QuickSortMultiThreading right = new QuickSortMultiThreading(p + 1, end, arr);        List<Task> tasks = new List<Task>();        tasks.Add(Task.Run(() => left.Sort()));        tasks.Add(Task.Run(() => right.Sort()));        Task.WaitAll(tasks.ToArray());    }}// Driver Codeclass Program {    static void Main(string[] args) {        int n = 7;        int[] arr = { 54, 64, 95, 82, 12, 32, 63 };        QuickSortMultiThreading quickSort = new QuickSortMultiThreading(0, n - 1, arr);        quickSort.Sort();        for (int i = 0; i < n; i++) {            Console.Write(arr[i] + " ");        }    }}// This code is contributed by shivhack999 | 
Javascript
class QuickSortMultiThreading {    constructor(start, end, arr) {        this.start = start;        this.end = end;        this.arr = arr;    }         // Finding random pivoted and partition    // array on a pivot.    // There are many different    // partitioning algorithms.    partition(start, end, arr) {        let i = start;        let j = end;                  // Decide random pivot        const pivoted = Math.floor(Math.random() * (j - i + 1)) + i;        [arr[j], arr[pivoted]] = [arr[pivoted], arr[j]];        j--;                // Start partitioning        while (i <= j) {            if (arr[i] <= arr[end]) {                i++;                continue;            }            if (arr[j] >= arr[end]) {                j--;                continue;            }            [arr[j], arr[i]] = [arr[i], arr[j]];            j--;            i++;        }        [arr[j + 1], arr[end]] = [arr[end], arr[j + 1]];        return j + 1;    }         // Function to implement    // QuickSort method    operator() {        if (this.start >= this.end) {            return;        }        const p = this.partition(this.start, this.end, this.arr);        const left = new QuickSortMultiThreading(this.start, p - 1, this.arr);        const right = new QuickSortMultiThreading(p + 1, this.end, this.arr);        const numThreads = 2; // Number of threads for parallel sections        const promises = [            new Promise(resolve => resolve(left.compute())),            new Promise(resolve => resolve(right.compute()))        ];        return Promise.all(promises);    }}const n = 7;const arr = [54, 64, 95, 82, 12, 32, 63];const mainInstance = new QuickSortMultiThreading(0, n - 1, arr);await mainInstance.operator();console.log(arr.join(' ')); | 
12 32 54 63 64 82 95
Time Complexity: O(N*log N) 
Auxiliary Space: O(N)
 
				
					


