Parallel Quick Sort: Mechanism, Complexity Analysis & Interactive Visualizer
Parallel Quick Sort
A concurrent divide-and-conquer algorithm: partitions the array around pivot elements, spawning child threads to sort sub-partitions in parallel branches of the execution tree.
How it works
Quicksort's divide-and-conquer strategy makes it exceptionally easy to parallelize. Unlike Merge Sort (which does work *after* recursive joins), Quicksort does its work (partitioning) *before* recursion. Parallel Quick Sort runs partition tasks concurrently:
- Pivot & Partition: Select a pivot and partition the array segment into two ranges: elements smaller than the pivot, and elements larger than the pivot. This step is performed sequentially on a single thread.
- Parallel Task Spawn: Instead of sorting the left and right sub-arrays sequentially, we spawn a new execution thread to sort the right sub-array, while the current thread processes the left sub-array.
- Grain-Size Threshold: If sub-array partition sizes fall below a certain threshold (e.g. 1000 elements), the overhead of creating new threads is larger than the benefit. The algorithm therefore switches to standard sequential Quicksort or Insertion Sort for small segments.
- Join: Wait for all concurrent sub-tasks to complete, completing the sort without requiring a merge step.
Complexity
Interactive visualization
Pseudocode
procedure parallelQuickSort(A, left, right): if right - left < threshold: sequentialQuickSort(A, left, right) else: pivotIdx ← partition(A, left, right) spawn parallelQuickSort(A, left, pivotIdx - 1) parallelQuickSort(A, pivotIdx + 1, right) sync # Wait for spawned branch to finish
JavaScript implementation
// Parallel Quicksort using ES6 asynchronous Promise tasks async function parallelQuickSort(arr, left = 0, right = arr.length - 1) { if (left >= right) return; // Partition size threshold for spawning new worker threads const threshold = 500; if (right - left < threshold) { sequentialQuickSort(arr, left, right); return; } const pivotIdx = partition(arr, left, right); await Promise.all([ spawnWorkerTask(arr, left, pivotIdx - 1), parallelQuickSort(arr, pivotIdx + 1, right) ]); }
Pros and cons
Pros
- Stunningly fast in-place parallel sort.
- Requires very little auxiliary space (reuses same memory space).
- Highly effective load-balancing when pivots partition evenly.
Cons
- Unstable sorting order.
- Degrades to \(O(n²)\) if pivots divide partitioning poorly (e.g. sorted arrays).
- Requires thread synchronization barriers (join steps).
When (not) to use it
- Multi-core frameworks: Broadly used in high-performance computing, GPU shaders, and system libraries where sorting speed is critical.
- Safety-critical systems: Avoid when stable sorting is required; choose Parallel Merge Sort instead.
Related reading
Sleep Sort: Mechanism, Complexity Analysis & Interactive Visualizer
A unique concurrency-based sorting algorithm: spawns a separate thread for each element, sleeping for a duration proportional to the element value before writing it to the output.
By Md. Harun-Or-Roshid
Cube Sort: Mechanism, Complexity Analysis & Interactive Visualizer
A parallel dimension sorting algorithm: organizes elements in a 3D coordinate cube and sorts vectors along the height, width, and depth axes sequentially to achieve sorted order.
By Md. Harun-Or-Roshid
Patience Sort: Mechanism, Complexity Analysis & Interactive Visualizer
A card-game inspired sorting algorithm: distributes elements onto a series of piles such that each pile's top is \(\ge\) the incoming value, then performs a multi-way merge across pile tops.
By Md. Harun-Or-Roshid
Library Sort: Mechanism, Complexity Analysis & Interactive Visualizer
A gapped variation of Insertion Sort: leaves empty slots (gaps) in the array, allowing elements to be inserted in \(O(1)\) shift time on average by avoiding massive shifts.
By Md. Harun-Or-Roshid