Skip to content
intermediatePhase 3 · Sorting & Searching

Quick Sort

Learn efficient in-place sorting with average O(n log n) performance.

1h
4 problems
Topic Progress0%

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

  1. Choose Pivot: Select an element (first, last, random, or median)
  2. Partition: Rearrange so elements < pivot are left, elements > pivot are right
  3. 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

  1. Partition around pivot
  2. If pivot index equals k, return pivot
  3. If k < pivot index, recurse on left partition
  4. 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

  1. Find kth largest/smallest element
  2. Median finding
  3. Top k elements (with partial sort)
  4. 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

Press Play or Step to begin
CurrentFound / DoneEliminatedUnvisited

Practice Problems

0/3solved
Sort Colors (Dutch National Flag)
Three-Way Partition

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
Kth Largest Element in an Array
Quick Select

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
Top K Frequent Elements
Quick Select + HashMap

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?

Question 1 options

2. What is the space complexity of quicksort?

Question 2 options

3. What is the primary purpose of Quick Sort?

Question 3 options

4. What is a common mistake when implementing Quick Sort?

Question 4 options

Flashcards

Question

What is the average time complexity of quicksort?

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?

Answer

By randomly selecting pivot, we avoid consistent bad partitions that occur with deterministic pivot choices on sorted data.

Question

What is Quick Sort?

Answer

Quick Sort is a key concept in software engineering.

Question

When to use Quick Sort?

Answer

Use Quick Sort when building production systems that require reliability, scalability, and maintainability.

Question

Quick Sort best practices

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:

  1. Choose pivot element
  2. Partition: elements < pivot left, > pivot right
  3. 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