1. Introduction
Quick Sort is a widely-used, efficient, and comparison-based divide-and-conquer sorting algorithm. It was developed by Tony Hoare in 1959.
Quick Sort works by selecting a pivot element from the array, partitioning the remaining elements into two sub-arrays:
- Elements less than or equal to the pivot go to the left
- Elements greater than the pivot go to the right
The same process is then recursively applied to the sub-arrays.
2. Step-by-Step Explanation of the Algorithm
Let’s break down Quick Sort with clarity.
- Choose a pivot element
- Common choices: First element, last element, middle element, or a random one.
- Partition the array
- Rearrange elements so that all items smaller than the pivot come before it, and all larger ones come after.
- Recursively apply the same steps to the sub-arrays formed by partitioning.
- Base case: When the sub-array has one or no elements, it is already sorted.
3. Implementation
public class QuickSort { // Main function to initiate the sort public static void quickSort(int[] arr, int low, int high) { if (low < high) { // Find the pivot index after partition int pivotIndex = partition(arr, low, high); // Recursively sort elements before and after partition quickSort(arr, low, pivotIndex - 1); quickSort(arr, pivotIndex + 1, high); } } // Partitioning method private static int partition(int[] arr, int low, int high) { int pivot = arr[high]; // Choose the last element as pivot int i = low - 1; // Index of smaller element for (int j = low; j < high; j++) { // If current element is <= pivot if (arr[j] <= pivot) { i++; // Swap arr[i] and arr[j] int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } // Swap arr[i + 1] and pivot int temp = arr[i + 1]; arr[i + 1] = arr[high]; arr[high] = temp; return i + 1; // Return the partitioning index } // Utility method to print the array public static void printArray(int[] arr) { for (int item : arr) System.out.print(item + " "); System.out.println(); } // Driver method public static void main(String[] args) { int[] arr = { 10, 7, 8, 9, 1, 5 }; System.out.println("Original Array:"); printArray(arr); quickSort(arr, 0, arr.length - 1); System.out.println("Sorted Array:"); printArray(arr); } }
4. Explaination of the partition step
4.1 Purpose of the Partition Step
The partition step is the heart of Quick Sort. Its goal is to:
- Choose a pivot element.
- Reorder the array so that:
- All elements less than or equal to the pivot are placed to the left.
- All elements greater than the pivot are placed to the right.
- Return the final index of the pivot, which is now in its correct sorted position.
4.2 General Idea of Partition Algorithm
- Choose a pivot (commonly the last element).
- Initialize an index
i = low - 1
. It will mark the boundary for elements less than or equal to the pivot. - Iterate
j
fromlow
tohigh - 1
:- If
arr[j] <= pivot
:- Increment
i
- Swap
arr[i]
witharr[j]
- Increment
- If
- Finally, place the pivot in its correct position by swapping
arr[i+1]
witharr[high]
.
4.3 Step-by-Step Example with Visual Representation
Let’s walk through an example.
Input Array:
int[] arr = { 10, 80, 30, 90, 40, 50, 70 };
Parameters:
low = 0
high = 6
- So
pivot = arr[6] = 70
Initial Setup:
Array: [10, 80, 30, 90, 40, 50, 70] Indexes: 0 1 2 3 4 5 6 i = -1 pivot = 70 (arr[6])
Step-by-Step Execution:
j = 0
arr[0] = 10 <= 70
→ yes- Increment
i = 0
- Swap
arr[0]
witharr[0]
→ no change
i=0 [10, 80, 30, 90, 40, 50, 70]
j = 1
arr[1] = 80 > 70
→ skip
i=0 [10, 80, 30, 90, 40, 50, 70]
j = 2
arr[2] = 30 <= 70
→ yes- Increment
i = 1
- Swap
arr[1]
witharr[2]
i=1 [10, 30, 80, 90, 40, 50, 70]
j = 3
arr[3] = 90 > 70
→ skip
i=1 [10, 30, 80, 90, 40, 50, 70]
j = 4
arr[4] = 40 <= 70
→ yes- Increment
i = 2
- Swap
arr[2]
witharr[4]
i=2 [10, 30, 40, 90, 80, 50, 70]
j = 5
arr[5] = 50 <= 70
→ yes- Increment
i = 3
- Swap
arr[3]
witharr[5]
i=3 [10, 30, 40, 50, 80, 90, 70]
After Loop Ends:
i = 3
- Swap
arr[i+1]
witharr[high]
→ Swaparr[4]
witharr[6]
(pivot)
[10, 30, 40, 50, 70, 90, 80]
Pivot (70) is now at index 4, and everything to the left of it is <= 70
, everything to the right is > 70
.
5. Visual Summary of Each Step
Step 0: Initial 10 80 30 90 40 50 70 ^ ^ pivot = 70 low high Step 1: arr[0] = 10 <= 70 → swap with itself 10 80 30 90 40 50 70 ↑ i Step 2: arr[1] = 80 > 70 → skip i stays at 0 Step 3: arr[2] = 30 <= 70 → swap arr[1] and arr[2] 10 30 80 90 40 50 70 ↑ i Step 4: arr[3] = 90 > 70 → skip Step 5: arr[4] = 40 <= 70 → swap arr[2] and arr[4] 10 30 40 90 80 50 70 ↑ i Step 6: arr[5] = 50 <= 70 → swap arr[3] and arr[5] 10 30 40 50 80 90 70 ↑ i Final: swap arr[4] with pivot (arr[6]) 10 30 40 50 70 90 80 ↑ pivotIndex = 4
6. Time Complexity
Case | Time Complexity |
Best | O(n log n) — when partition splits are balanced |
Average | O(n log n) |
Worst | O(n²) — when the smallest or largest element is always picked as pivot (unbalanced partitions) |
Note: Worst case is rare in practice if pivot is chosen well (e.g., using randomized or median-of-three approach)
7. Space Complexity
- O(log n) due to recursive calls on the stack (for balanced partitions)
- In-place sorting: No extra array used
8. Advantages of Quick Sort
- Faster in practice than other O(n log n) algorithms like Merge Sort due to better cache performance.
- In-place sort (no extra memory needed like merge sort).
- Tail recursion optimizations are possible.
9. Disadvantages of Quick Sort
- Not stable (relative ordering of equal elements not preserved).
- Worst-case time is O(n²), though can be avoided with better pivot strategies.
- Recursive implementation can lead to stack overflow on very large datasets.
10. When to Use Quick Sort
- When in-place sorting is required and stability is not a concern.
- When average-case performance is more critical than worst-case.
- When performance is paramount and data fits in memory.