DSA Notes
A complete comparison of all sorting algorithms — performance tables at every scale, side-by-side feature comparison, decision flowchart for choosing the right sort, real-world algorithm selection in Python/Java/C++, and common sorting mistakes to avoid.
Master Comparison Table
| Algorithm | Best | Average | Worst | Space | Stable | Adaptive | Type |
|---|---|---|---|---|---|---|---|
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | ✅ | ✅ | Comparison |
| Selection Sort | O(n²) | O(n²) | O(n²) | O(1) | ❌ | ❌ | Comparison |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | ✅ | ✅ | Comparison |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | ✅ | ❌ | Comparison |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | ❌ | ❌ | Comparison |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | ❌ | ❌ | Comparison |
| Counting Sort | O(n+k) | O(n+k) | O(n+k) | O(n+k) | ✅ | - | Non-comp |
| Radix Sort | O(nk) | O(nk) | O(nk) | O(n+k) | ✅ | - | Non-comp |
| TimSort* | O(n) | O(n log n) | O(n log n) | O(n) | ✅ | ✅ | Hybrid |
*Python's built-in sort (Merge Sort + Insertion Sort hybrid)
Decision Flowchart
| START | What are you sorting? |
| │ └── YES | Counting Sort O(n+k) ✅ |
| │ └── YES | Radix Sort O(nk) ✅ |
| │ └── YES | Insertion Sort ✅ (low overhead) |
| │ └── YES | Insertion Sort or TimSort ✅ (O(n) best case) |
| │ ├── YES + Memory available | Merge Sort ✅ |
| │ └── YES + Python/Java | Use built-in sort() ✅ (TimSort, stable) |
| │ ├── + Memory is tight | Heap Sort ✅ |
| │ └── + Memory available | Merge Sort ✅ |
Feature Comparison: Key Questions
"Do I need stability?"
Stability preserves relative order of equal elements:
| Input | [(Alice, 85), (Bob, 72), (Charlie, 85)] |
| Stable | [(Bob, 72), (Alice, 85), (Charlie, 85)] ← Alice before Charlie |
| Unstable | [(Bob, 72), (Charlie, 85), (Alice, 85)] ← order flipped |
Use Merge Sort, Insertion Sort, Counting Sort, or TimSort.
"Is memory available?"
- O(1) space: Heap Sort, Selection Sort, Insertion Sort, Bubble Sort
- O(log n) space: Quick Sort (recursion stack)
- O(n) space: Merge Sort, Counting Sort, Radix Sort
"Is worst-case guarantee critical?"
- Quick Sort: O(n²) worst case (prevented with randomization, but not eliminated)
- Merge Sort, Heap Sort: O(n log n) always — no bad input exists
"Is the data nearly sorted?"
- Use Insertion Sort (O(n) best case) or TimSort
- Quick Sort, Merge Sort, Heap Sort: still O(n log n) even on sorted data
Real-World Language Implementations
Python
Java
int[] arr = {3, 1, 4, 1, 5};
Arrays.sort(arr); // Dual-pivot Quicksort for primitives, O(n log n)
Integer[] arr2 = {3, 1, 4, 1, 5};
Arrays.sort(arr2); // TimSort for object arrays, stable
List<Integer> list = Arrays.asList(3, 1, 4, 1, 5);
Collections.sort(list); // TimSort, stable
// Java's choice: Quicksort for primitives (fast, no stability needed)
// TimSort for objects (stability required for Comparable)C++
#include <algorithm>
std::vector<int> v = {3, 1, 4, 1, 5};
std::sort(v.begin(), v.end()); // Introsort, not stable
std::stable_sort(v.begin(), v.end()); // Merge sort, stable, O(n log n)C++'s std::sort uses Introsort — a hybrid of Quick Sort, Heap Sort, and Insertion Sort:
- Quick Sort as default (fast in practice)
- Switches to Heap Sort if recursion depth exceeds 2×log(n) (prevents O(n²) worst case)
- Switches to Insertion Sort for small subarrays (low overhead)
- Result: O(n log n) guaranteed, with Quick Sort's practical speed
Common Mistakes
Mistake 1 — Using O(n²) sort for large data
Mistake 2 — Not using the built-in sort when available
# Unless implementing for learning: always use built-in first
# Python's sort() is implemented in C and faster than any pure Python sortMistake 3 — Assuming Quick Sort is always best
Quick Sort is best for:
- Random or near-random data
- Primitive data (no stability needed)
- Memory-constrained environments
Not best for:
- Sorted or nearly-sorted data (use Insertion Sort/TimSort)
- Data requiring stable sort (use Merge Sort)
- Security-sensitive applications (sorted adversarial input causes O(n²) — use randomized version)
Mistake 4 — Using Counting Sort when range is huge
When Each Algorithm Shines
| Algorithm | Its Best Use Case |
|---|---|
| Bubble Sort | Teaching, detecting if array is sorted |
| Selection Sort | Minimizing writes to slow memory (flash) |
| Insertion Sort | n < 32, nearly sorted data, online/streaming |
| Merge Sort | Stable O(n log n) needed, linked lists, external sort |
| Quick Sort | General-purpose, cache-sensitive, in-memory |
| Heap Sort | O(n log n) guaranteed AND O(1) space needed simultaneously |
| Counting Sort | Small integer range (grades, ages, characters) |
| Radix Sort | Large integer range, phone numbers, IDs |
| TimSort | Real-world data with natural runs (Python/Java default) |
Summary
For interviews: Know the Big-3: Merge Sort, Quick Sort, and Heap Sort deeply. Know Counting Sort and Radix Sort as non-comparison alternatives.
For production: Use the language's built-in sort — it is almost certainly the best choice (TimSort in Python/Java, Introsort in C++).
The key insight: There is no universally best sorting algorithm. The right choice depends on: data size, value range, whether stability is needed, memory constraints, and data distribution.
*Next Lesson: Sorting Interview Problems*
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Sorting Algorithm Comparison — The Complete Decision Guide.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, sorting, comparison, sorting algorithm comparison — the complete decision guide
Related Data Structures & Algorithms Topics