Quick Sort Fundamentals
Quick sort is a divide-and-conquer algorithm that picks a pivot, partitions array around it, then recursively sorts subarrays.
Algorithm Steps
- Choose Pivot: Select an element (first, last, random, or median)
- Partition: Rearrange so elements < pivot are left, elements > pivot are right
- Recurse: Recursively sort left and right partitions
Visual Example
Array: [3, 6, 8, 10, 1, 2, 1]
Pivot: 10 (last element)
Partition:
[3, 6, 8, 1, 2, 1] [10]
(< pivot) (pivot)
Recurse on left:
[3, 6, 8, 1, 2, 1]
Pivot: 1
[1] [3, 6, 8, 2] [1]
Continue until sorted: [1, 1, 2, 3, 6, 8, 10]
Lomuto Partition Scheme
public void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pivotIndex = partition(arr, low, high);
quickSort(arr, low, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, high);
}
}
private int partition(int[] arr, int low, int high) {
int pivot = arr[high]; // Choose last element as pivot
int i = low - 1; // Pointer for smaller elements
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, high); // Place pivot in correct position
return i + 1;
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
Hoare Partition Scheme
More efficient, swaps fewer elements:
public void quickSortHoare(int[] arr, int low, int high) {
if (low < high) {
int pivotIndex = partitionHoare(arr, low, high);
quickSortHoare(arr, low, pivotIndex);
quickSortHoare(arr, pivotIndex + 1, high);
}
}
private int partitionHoare(int[] arr, int low, int high) {
int pivot = arr[low + (high - low) / 2];
int i = low - 1;
int j = high + 1;
while (true) {
do { i++; } while (arr[i] < pivot);
do { j--; } while (arr[j] > pivot);
if (i >= j) return j;
swap(arr, i, j);
}
}
Randomized Quick Sort
Avoids worst-case by random pivot selection:
private int partitionRandom(int[] arr, int low, int high) {
int random = low + (int)(Math.random() * (high - low + 1));
swap(arr, random, high);
return partition(arr, low, high);
}
Complexity Analysis
| Case | Time | Space | When |
|---|---|---|---|
| Best | O(n log n) | O(log n) | Pivot always divides evenly |
| Average | O(n log n) | O(log n) | Random input |
| Worst | O(n²) | O(n) | Already sorted (with bad pivot) |
Quick Select (Selection Algorithm)
Quick select is a variation of quicksort that finds the kth smallest element without fully sorting the array.
Algorithm
- Partition around pivot
- If pivot index equals k, return pivot
- If k < pivot index, recurse on left partition
- If k > pivot index, recurse on right partition
Java Implementation
public int quickSelect(int[] arr, int k) {
return quickSelect(arr, 0, arr.length - 1, k - 1);
}
private int quickSelect(int[] arr, int low, int high, int k) {
if (low == high) return arr[low];
int pivotIndex = partition(arr, low, high);
if (k == pivotIndex) {
return arr[k];
} else if (k < pivotIndex) {
return quickSelect(arr, low, pivotIndex - 1, k);
} else {
return quickSelect(arr, pivotIndex + 1, high, k);
}
}
Iterative Quick Select
public int quickSelectIterative(int[] arr, int k) {
int low = 0, high = arr.length - 1;
while (low <= high) {
int pivotIndex = partition(arr, low, high);
if (pivotIndex == k) {
return arr[k];
} else if (pivotIndex < k) {
low = pivotIndex + 1;
} else {
high = pivotIndex - 1;
}
}
throw new IllegalArgumentException("k is out of bounds");
}
Applications of Quick Select
- Find kth largest/smallest element
- Median finding
- Top k elements (with partial sort)
- Statistics (percentiles, quartiles)
Complexity
| Case | Time | Space |
|---|---|---|
| Best | O(n) | O(1) |
| Average | O(n) | O(1) |
| Worst | O(n²) | O(n) |
When to Use Quick Select
- Finding single element (kth smallest/largest)
- Finding median
- Don't need full sort
- Memory is limited
Interactive Visualization
Quick Sort Partitioning
Practice Problems
Given an array with objects colored red, white, or blue (0, 1, 2), sort them in-place.
Example:
Input: nums = [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
Three-way partition.
Optimal Solution — O(n) time, O(1) space
Three pointers: low, mid, high
class Solution {
public void sortColors(int[] nums) {
int low = 0, mid = 0, high = nums.length - 1;
while (mid <= high) {
if (nums[mid] == 0) { swap(nums, low++, mid++); }
else if (nums[mid] == 1) { mid++; }
else { swap(nums, mid, high--); }
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp;
}
}Edge Cases:
- All same color
- Already sorted
- Single element
Given an integer array nums and an integer k, return the kth largest element.
Example:
Input: nums = [3,2,1,5,6,4], k = 2
Output: 5
Second largest is 5.
Optimal Solution — O(n) average time, O(log n) space
Quick select - O(n) average
class Solution {
public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, k - 1);
}
private int quickSelect(int[] nums, int lo, int hi, int k) {
if (lo == hi) return nums[lo];
int pivot = nums[hi];
int i = lo;
for (int j = lo; j < hi; j++) {
if (nums[j] > pivot) { swap(nums, i++, j); }
}
swap(nums, i, hi);
if (i == k) return nums[i];
else if (i < k) return quickSelect(nums, i + 1, hi, k);
else return quickSelect(nums, lo, i - 1, k);
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp;
}
}Edge Cases:
- k == 1
- k == n
- All same elements
Given an integer array nums and an integer k, return the k most frequent elements.
Example:
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
1 appears 3 times, 2 appears 2 times.
Optimal Solution — O(n) time, O(n) space
Bucket sort O(n) or quick select O(n) average
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> freq = new HashMap<>();
for (int n : nums) freq.merge(n, 1, Integer::sum);
List<Integer>[] bucket = new List[nums.length + 1];
for (Map.Entry<Integer, Integer> e : freq.entrySet()) {
int f = e.getValue();
if (bucket[f] == null) bucket[f] = new ArrayList<>();
bucket[f].add(e.getKey());
}
int[] result = new int[k];
int idx = 0;
for (int i = bucket.length - 1; i >= 0 && idx < k; i--) {
if (bucket[i] != null) {
for (int val : bucket[i]) {
if (idx < k) result[idx++] = val;
}
}
}
return result;
}
}Edge Cases:
- All unique
- All same
- k == distinct count
Quiz
1. What causes quicksort's worst-case O(n²) time complexity?
2. What is the space complexity of quicksort?
3. What is the primary purpose of Quick Sort?
4. What is a common mistake when implementing Quick Sort?
Flashcards
Question
What is the average time complexity of quicksort?
Click to reveal answer
Answer
O(n log n) - with good pivot selection, array is divided roughly in half each time.
Question
How does randomized quicksort avoid worst-case?
Click to reveal answer
Answer
By randomly selecting pivot, we avoid consistent bad partitions that occur with deterministic pivot choices on sorted data.
Question
What is Quick Sort?
Click to reveal answer
Answer
Quick Sort is a key concept in software engineering.
Question
When to use Quick Sort?
Click to reveal answer
Answer
Use Quick Sort when building production systems that require reliability, scalability, and maintainability.
Question
Quick Sort best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Quicksort is fast in practice despite O(n²) worst case
- 2.Pivot selection strategy is critical for performance
- 3.Randomized quicksort avoids worst-case on sorted data
- 4.Quick select finds kth element in O(n) average time
Interview Tips
- •Discuss pivot selection strategies and their tradeoffs
- •Explain why quicksort is often preferred over merge sort in practice
- •Mention quick select for kth element problems
- •Know both Lomuto and Hoare partition schemes
Cheat Sheet
Quick Sort Cheat Sheet
Algorithm:
- Choose pivot element
- Partition: elements < pivot left, > pivot right
- Recursively sort partitions
Partition (Lomuto):
int partition(int[] arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) swap(arr, ++i, j);
}
swap(arr, i + 1, high);
return i + 1;
}
Complexity:
- Time: O(n log n) avg, O(n²) worst
- Space: O(log n) avg
- Stable: No
Optimizations:
- Randomized pivot
- Median-of-three
- Insertion sort for small subarrays