Web Analytics

🔢 Counting Sort

Intermediate ~12 min read

You're grading 100 test papers, each scored 0-100. Instead of comparing scores, you have a smarter strategy: Count how many students got each score, then reconstruct the sorted list. No comparisons needed! That's Counting Sort - O(n) linear time!

The Tally Counter

Imagine a tally sheet with boxes for each possible score. Go through the papers once, making a tally mark for each score. Then read off the tallies in order!

The Strategy

  1. Find the range: Minimum to maximum values
  2. Count occurrences: How many times each value appears
  3. Reconstruct: Build sorted array from counts
  4. Done in O(n) time! No comparisons!

Key insight: When values are in a small range, counting beats comparing!

Breaking the O(n log n) Barrier!

The Breakthrough

All comparison-based sorts (Merge, Quick, Heap) have a theoretical lower bound of O(n log n).

Counting Sort breaks this barrier!

  • Comparison sorts: O(n log n) minimum
  • Counting Sort: O(n + k) where k = range
  • When k is small: Basically O(n)! 🚀

How? It doesn't compare elements - it counts them!

See It in Action

Watch how Counting Sort counts occurrences and reconstructs the sorted array:

Understanding the Process

  • Phase 1: Count occurrences - O(n)
  • Phase 2: Reconstruct sorted array - O(n + k)
  • Total: O(n + k) linear time!
  • Tally marks: Visual count of each value
  • No comparisons: Just counting!

The Code

Output
Click Run to execute your code
Two Versions: The basic version is simpler but not stable. The stable version uses cumulative counts and builds right-to-left to preserve the order of equal elements. This is crucial for Radix Sort!

Quick Quiz

  • Why can Counting Sort be O(n) when comparison sorts are O(n log n)?
    Show answer Counting Sort doesn't compare elements! It counts occurrences instead. The O(n log n) lower bound only applies to comparison-based sorting. By using a different approach (counting), we can beat this barrier for specific cases (small integer ranges).
  • When would Counting Sort be terrible?
    Show answer When the range is huge! If you're sorting 100 numbers with values from 1 to 1,000,000,000, you'd need a billion-element count array. That's impractical! Counting Sort only works well when the range (k) is small compared to the number of elements (n).

Why O(n + k)?

Let's break down the complexity:

Step Time Why
Find min/max O(n) Scan array once
Count occurrences O(n) Scan array once, increment counts
Reconstruct array O(n + k) Iterate through counts (k), place elements (n)
Total O(n + k) Linear when k is small!
Space O(k) Count array of size k

✅ When k is Small

If k (range) is O(n) or smaller:

  • Time: O(n + k) = O(n) ✓
  • Example: Sorting 1 million ages (k=120) → O(1,000,000) linear!
  • Faster than: O(n log n) = O(20,000,000) for comparison sorts!

⚠️ When k is Large

If k (range) is much larger than n:

  • Time: O(n + k) ≈ O(k) - dominated by range!
  • Space: O(k) - huge count array!
  • Example: Sorting 100 numbers (n=100) with range 1-1,000,000,000 (k=1B)
  • Result: Terrible! Use comparison sort instead!

When to Use Counting Sort

✅ Perfect For:

  • Ages: 0-120 (k=120)
  • Grades: 0-100 or A-F (k=100 or 5)
  • Pixel intensities: 0-255 (k=255)
  • Small integers: Range is reasonable
  • Foundation for Radix Sort: Digit-by-digit sorting

Rule of thumb: If k ≤ n, Counting Sort wins!

❌ Terrible For:

  • Arbitrary large integers: Range too big
  • Floating-point numbers: Not integers
  • Strings: Use Radix Sort instead
  • Sparse ranges: Few values in huge range

Example: Sorting [1, 1000000, 5, 999999] needs 1M count array for 4 numbers!

Counting Sort vs Others

Feature Quick Sort Heap Sort Counting Sort
Type Comparison Comparison Non-comparison ✓
Time (avg) O(n log n) O(n log n) O(n + k) ✓
Space O(log n) ✓ O(1) ✓ O(k)
Stable No No Yes (stable version) ✓
Use When General purpose Guaranteed + in-place Small integer range ✓

The Verdict

Counting Sort is a specialist:

  • ✅ Unbeatable for small ranges - O(n) linear!
  • ✅ Foundation for Radix Sort
  • ✅ Stable version available
  • ⚠️ Only works for integers in small ranges
  • ⚠️ Space usage depends on range, not array size

Know your data, choose your algorithm!

The Stable Version

Why do we need a stable version?

Stability Matters for Radix Sort

When sorting by multiple keys (like sorting by last name, then first name), we need stability:

  • Example: Sorting students by grade, then by name
  • First: Sort by name (stable)
  • Then: Sort by grade (must be stable!)
  • Result: Students with same grade are still sorted by name

Radix Sort uses Counting Sort repeatedly for each digit - stability is crucial!

The stable version uses cumulative counts:

How Cumulative Counts Work

  1. Count occurrences: count[i] = how many elements equal i
  2. Make cumulative: count[i] += count[i-1]
  3. Now count[i] = how many elements ≤ i
  4. Build output: Right to left, place each element at count[value]-1
  5. Result: Stable! Equal elements maintain original order

Common Misconceptions

❌ Misconception 1: "Counting Sort works for any data"

Reality: Only for integers in a small range!

  • Integers: Yes ✓
  • Floats: No (can convert to integers)
  • Strings: No (use Radix Sort)
  • Objects: No (unless you extract integer keys)
  • Large range: No (space explosion!)

It's a specialist tool, not a general-purpose sort!

❌ Misconception 2: "Counting Sort is always faster"

Reality: Only when k (range) is small!

  • Small range (k ≤ n): Counting Sort wins! O(n) vs O(n log n)
  • Large range (k >> n): Comparison sorts win! O(n log n) vs O(k)
  • Example 1: 1M ages (n=1M, k=120) → Counting wins!
  • Example 2: 100 numbers, range 1-1B (n=100, k=1B) → Quick Sort wins!

Analyze your data before choosing!

❌ Misconception 3: "Counting Sort is in-place"

Reality: Needs O(k) extra space!

  • Count array: Size k (range)
  • Output array: Size n (stable version)
  • Total space: O(n + k)
  • Not in-place: Unlike Heap Sort or Quick Sort

Trade-off: Speed (O(n)) for space (O(k))

❌ Misconception 4: "Counting Sort is the fastest sort"

Reality: Fastest for its specific use case!

  • For small ranges: Yes, unbeatable!
  • For general data: No, use comparison sorts
  • For strings: No, use Radix Sort
  • For large ranges: No, terrible!

Every algorithm has its niche!

💡 Key Takeaway

Counting Sort is a game-changer for small ranges:

  • ✅ O(n) linear time - breaks O(n log n) barrier!
  • ✅ Non-comparison based - counts instead of compares
  • ✅ Stable version available - crucial for Radix Sort
  • ⚠️ Only for integers in small ranges
  • ⚠️ Space usage depends on range

Understanding Counting Sort teaches you that sometimes, a specialized tool beats a general-purpose one!

Summary

The 3-Point Counting Sort Guide

  1. Strategy: Count occurrences, reconstruct - no comparisons needed!
  2. Complexity: O(n + k) linear when k is small - breaks O(n log n) barrier!
  3. Trade-off: Speed (O(n)) vs limited use case (small integer ranges)

Interview tip: Mention Counting Sort for sorting integers in small ranges. Explain why it's O(n), when to use it, and why it needs stability for Radix Sort!

What's Next?

You've learned the first non-comparison sort! Next: Radix Sort - extending Counting Sort to handle larger ranges by sorting digit-by-digit!

Practice: Implement Counting Sort for sorting students by age. Then try the stable version for sorting by grade, then by name!