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 approach import 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 approach import random from concurrent.futures import ThreadPoolExecutor Â
class 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 Code if __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 approach using 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 Code class 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)
Â