Bird
Raised Fist0
DSA Rustprogramming~15 mins

Counting Sort Algorithm in DSA Rust - Deep Dive

Choose your learning style10 modes available
Overview - Counting Sort Algorithm
What is it?
Counting Sort is a way to sort numbers by counting how many times each number appears. It works best when the numbers are within a small range. Instead of comparing numbers directly, it uses their counts to place them in order. This makes sorting very fast for certain types of data.
Why it matters
Without Counting Sort, sorting numbers with many repeats or small ranges would take longer using usual methods. Counting Sort solves this by using counting to sort quickly and efficiently. This helps in situations like sorting exam scores or ages where values repeat and are limited. Without it, programs would run slower and use more resources.
Where it fits
Before learning Counting Sort, you should know basic sorting methods like Bubble Sort or Insertion Sort. After Counting Sort, you can learn more advanced sorting algorithms like Radix Sort or Bucket Sort that build on similar ideas.
Mental Model
Core Idea
Counting Sort sorts by counting how many times each number appears and then placing numbers in order based on these counts.
Think of it like...
Imagine you have a box of colored beads and you want to sort them by color. Instead of sorting one by one, you count how many beads of each color you have, then line them up color by color using those counts.
Input array: [4, 2, 2, 8, 3, 3, 1]

Count array (index = number):
Index: 0 1 2 3 4 5 6 7 8
Count: 0 1 2 2 1 0 0 0 1

Cumulative count:
Index: 0 1 2 3 4 5 6 7 8
Count: 0 1 3 5 6 6 6 6 7

Sorted output: [1, 2, 2, 3, 3, 4, 8]
Build-Up - 6 Steps
1
FoundationUnderstanding Counting Sort Basics
🤔
Concept: Counting Sort uses a count array to track how many times each number appears.
Start with an input array of numbers. Create a count array with size equal to the maximum number plus one. Initialize all counts to zero. For each number in the input, increase its count by one in the count array.
Result
You get a count array showing how many times each number appears.
Understanding that counting occurrences is the first step to sorting without comparing elements directly.
2
FoundationBuilding the Cumulative Count Array
🤔
Concept: Transform the count array into a cumulative count array to find positions for each number.
Modify the count array so each element at index i contains the sum of counts up to i. This tells where each number should be placed in the sorted output.
Result
A cumulative count array that helps place numbers in order.
Knowing cumulative counts lets you map numbers to their correct sorted positions efficiently.
3
IntermediatePlacing Elements into Sorted Output
🤔Before reading on: Do you think placing elements from left to right or right to left affects the stability of Counting Sort? Commit to your answer.
Concept: Use the cumulative count array to place each element from the input into the correct position in the output array.
Traverse the input array from right to left. For each element, use the cumulative count to find its position in the output array. Place it there and decrease the count by one.
Result
A sorted output array with elements in correct order, preserving duplicates' original order.
Understanding traversal direction is key to maintaining stability, which keeps equal elements in their original order.
4
IntermediateHandling Range and Memory Constraints
🤔Before reading on: Do you think Counting Sort works well for very large numbers with big gaps? Commit to your answer.
Concept: Counting Sort requires extra memory proportional to the range of input values, which can be large.
If the input numbers have a large range with big gaps, the count array becomes large and inefficient. Counting Sort is best when the range is small or moderate.
Result
Counting Sort may use too much memory or be slow if the range is huge.
Knowing the limits of Counting Sort helps choose the right sorting method for different data.
5
AdvancedImplementing Counting Sort in Rust
🤔Before reading on: Do you think Rust's ownership and borrowing rules affect how we implement Counting Sort? Commit to your answer.
Concept: Implement Counting Sort in Rust using vectors and careful handling of mutable references.
fn counting_sort(arr: &[usize]) -> Vec { let max = *arr.iter().max().unwrap_or(&0); let mut count = vec![0; max + 1]; for &num in arr { count[num] += 1; } for i in 1..=max { count[i] += count[i - 1]; } let mut output = vec![0; arr.len()]; for &num in arr.iter().rev() { count[num] -= 1; output[count[num]] = num; } output } fn main() { let input = vec![4, 2, 2, 8, 3, 3, 1]; let sorted = counting_sort(&input); println!("{:?}", sorted); }
Result
[1, 2, 2, 3, 3, 4, 8]
Understanding Rust's ownership and iteration methods helps write safe and efficient Counting Sort code.
6
ExpertOptimizing Counting Sort for Stability and Speed
🤔Before reading on: Can you think of a way to optimize Counting Sort to handle negative numbers or non-integer keys? Commit to your answer.
Concept: Counting Sort can be adapted for negative numbers by shifting values and combined with other algorithms for complex data.
To handle negative numbers, find the minimum value and shift all numbers by adding its absolute value to make them non-negative. Then apply Counting Sort. For non-integer keys, Counting Sort is not suitable directly; use Radix Sort or Bucket Sort instead.
Result
Counting Sort can be extended to more cases but requires careful adjustments.
Knowing how to adapt Counting Sort expands its usefulness beyond simple positive integers.
Under the Hood
Counting Sort works by creating a frequency array that counts how many times each value appears. Then it transforms this into a cumulative count array that tells the exact position of each value in the sorted output. By placing elements from the input into the output array using these positions, it sorts without comparing elements directly. This avoids the usual comparison-based sorting steps and runs in linear time relative to input size and range.
Why designed this way?
Counting Sort was designed to sort integers efficiently when the range is small. Traditional comparison sorts take at least n log n time, but Counting Sort achieves linear time by using extra memory to count occurrences. This tradeoff was chosen to speed up sorting in cases like exam scores or small-range data where comparisons are costly.
Input array
  ↓
Count array (frequency)
  ↓ (prefix sum)
Cumulative count array
  ↓ (place elements)
Sorted output array
Myth Busters - 3 Common Misconceptions
Quick: Does Counting Sort work well for sorting floating-point numbers? Commit to yes or no before reading on.
Common Belief:Counting Sort can sort any type of numbers quickly.
Tap to reveal reality
Reality:Counting Sort only works efficiently for integers within a small range, not floating-point numbers or large ranges.
Why it matters:Using Counting Sort on unsuitable data wastes memory and time, leading to poor performance.
Quick: Is Counting Sort always stable regardless of implementation? Commit to yes or no before reading on.
Common Belief:Counting Sort is always stable by default.
Tap to reveal reality
Reality:Counting Sort is stable only if elements are placed into the output array from right to left using the cumulative counts.
Why it matters:Incorrect implementation can break stability, causing equal elements to lose their original order, which matters in many applications.
Quick: Does Counting Sort use less memory than comparison-based sorts? Commit to yes or no before reading on.
Common Belief:Counting Sort always uses less memory than other sorting algorithms.
Tap to reveal reality
Reality:Counting Sort uses extra memory proportional to the range of input values, which can be large and more than comparison sorts.
Why it matters:Ignoring memory use can cause crashes or inefficiency on large or sparse data.
Expert Zone
1
Counting Sort's stability depends on the direction of input traversal when placing elements into the output array.
2
The algorithm's time complexity is O(n + k), where n is input size and k is the range, so large ranges can degrade performance.
3
Counting Sort can be combined with Radix Sort to sort large numbers or strings efficiently by sorting digit by digit.
When NOT to use
Avoid Counting Sort when the input range is very large or unknown, or when sorting non-integer data. Use comparison-based sorts like Quick Sort or Merge Sort, or specialized algorithms like Radix Sort for strings and large numbers.
Production Patterns
Counting Sort is used in systems where input values are limited and repeated, such as grading systems, histogram computations, and as a subroutine in Radix Sort for sorting large datasets efficiently.
Connections
Radix Sort
Counting Sort is used as a stable subroutine within Radix Sort to sort digits.
Understanding Counting Sort helps grasp how Radix Sort achieves fast sorting of large numbers by sorting digit by digit.
Histogram Analysis
Counting Sort's counting step is similar to building a histogram of data frequencies.
Knowing Counting Sort deepens understanding of histograms, which are used in statistics and image processing.
Inventory Management
Counting Sort's counting and ordering process resembles tracking and organizing stock quantities by item type.
Recognizing this connection shows how sorting algorithms relate to real-world counting and organizing tasks.
Common Pitfalls
#1Trying to use Counting Sort on data with a huge range causing excessive memory use.
Wrong approach:let max = 1_000_000_000; let mut count = vec![0; max + 1]; // huge memory allocation // rest of counting sort code
Correct approach:Use a different sorting algorithm like Quick Sort or Merge Sort for large ranges. // or Use Radix Sort if sorting large numbers digit by digit.
Root cause:Misunderstanding that Counting Sort's memory depends on the range, not just input size.
#2Placing elements from left to right in output array, breaking stability.
Wrong approach:for &num in arr.iter() { count[num] -= 1; output[count[num]] = num; }
Correct approach:for &num in arr.iter().rev() { count[num] -= 1; output[count[num]] = num; }
Root cause:Not realizing that traversal direction affects the order of equal elements.
#3Not handling empty input arrays causing panic on max calculation.
Wrong approach:let max = *arr.iter().max().unwrap(); // panics if arr is empty
Correct approach:let max = *arr.iter().max().unwrap_or(&0); // safely handles empty input
Root cause:Ignoring edge cases leads to runtime errors.
Key Takeaways
Counting Sort sorts by counting occurrences and using cumulative counts to place elements without comparisons.
It works best when input numbers are integers within a small range, using extra memory proportional to that range.
Stability depends on placing elements from right to left in the output array to preserve original order of duplicates.
Counting Sort is a building block for more complex algorithms like Radix Sort and is useful in real-world scenarios with limited value ranges.
Understanding its limits and memory use helps choose the right sorting method for different problems.

Practice

(1/5)
1. What is the main idea behind the Counting Sort Algorithm?
easy
A. Compare each element with every other element to sort
B. Count the occurrences of each element and use counts to place elements in order
C. Divide the array into halves and sort recursively
D. Swap adjacent elements if they are in wrong order repeatedly

Solution

  1. Step 1: Understand Counting Sort principle

    Counting sort counts how many times each value appears in the input.
  2. Step 2: Use counts to place elements

    These counts help place elements directly in the sorted output without comparisons.
  3. Final Answer:

    Count the occurrences of each element and use counts to place elements in order -> Option B
  4. Quick Check:

    Counting sort = Counting occurrences and placing [OK]
Hint: Counting sort uses counts, not comparisons, to sort [OK]
Common Mistakes:
  • Thinking counting sort compares elements
  • Confusing counting sort with quicksort or mergesort
  • Assuming counting sort works on all data types
2. Which of the following is the correct Rust syntax to create a vector of zeros with length 5 for counting sort?
easy
A. let counts = vec![0; 5];
B. let counts = vec(0, 5);
C. let counts = [0; 5];
D. let counts = vec::new(5, 0);

Solution

  1. Step 1: Recall Rust vector initialization

    In Rust, vec![value; size] creates a vector with repeated values.
  2. Step 2: Match syntax to create vector of zeros

    vec![0; 5] creates a vector with five zeros, perfect for counting sort.
  3. Final Answer:

    let counts = vec![0; 5]; -> Option A
  4. Quick Check:

    vec![0; 5] creates vector of 5 zeros [OK]
Hint: Use vec![value; size] to create repeated elements vector [OK]
Common Mistakes:
  • Using parentheses instead of square brackets for vec!
  • Confusing array syntax with vector syntax
  • Trying to use vec::new with parameters
3. What will be the output of the following Rust code snippet implementing counting sort on array [4, 2, 2, 8, 3, 3, 1]?
fn counting_sort(arr: &[usize]) -> Vec<usize> {
    let max = *arr.iter().max().unwrap();
    let mut counts = vec![0; max + 1];
    for &num in arr {
        counts[num] += 1;
    }
    let mut sorted = Vec::new();
    for (num, &count) in counts.iter().enumerate() {
        for _ in 0..count {
            sorted.push(num);
        }
    }
    sorted
}

fn main() {
    let arr = [4, 2, 2, 8, 3, 3, 1];
    let sorted = counting_sort(&arr);
    println!("{:?}", sorted);
}
medium
A. [0, 1, 2, 3, 4, 8]
B. [8, 4, 3, 3, 2, 2, 1]
C. [1, 3, 2, 4, 8]
D. [1, 2, 2, 3, 3, 4, 8]

Solution

  1. Step 1: Count occurrences of each number

    Input array: [4, 2, 2, 8, 3, 3, 1]. Counts: 1->1, 2->2, 3->2, 4->1, 8->1.
  2. Step 2: Build sorted vector using counts

    Push each number count times in order: 1, 2, 2, 3, 3, 4, 8.
  3. Final Answer:

    [1, 2, 2, 3, 3, 4, 8] -> Option D
  4. Quick Check:

    Sorted array = [1, 2, 2, 3, 3, 4, 8] [OK]
Hint: Counting sort output is sorted array with repeated elements [OK]
Common Mistakes:
  • Forgetting to repeat elements by their count
  • Outputting original array instead of sorted
  • Miscounting occurrences of elements
4. Identify the bug in this Rust counting sort code snippet and choose the fix:
fn counting_sort(arr: &[usize]) -> Vec<usize> {
    let max = arr.iter().max().unwrap();
    let mut counts = vec![0; *max];
    for &num in arr {
        counts[num] += 1;
    }
    let mut sorted = Vec::new();
    for (num, &count) in counts.iter().enumerate() {
        for _ in 0..count {
            sorted.push(num);
        }
    }
    sorted
}
medium
A. Change let max = arr.iter().max().unwrap(); to let max = *arr.iter().max().unwrap();
B. Change for &num in arr to for num in arr.iter()
C. Change vec![0; *max] to vec![0; *max + 1]
D. Change sorted.push(num) to sorted.push(count)

Solution

  1. Step 1: Check vector size for counts

    Vector size is *max, but max element index is *max, so size must be *max + 1 to include max.
  2. Step 2: Fix counts vector size

    Changing to vec![0; *max + 1] prevents out-of-bound errors when counting max element.
  3. Final Answer:

    Change vec![0; *max] to vec![0; *max + 1] -> Option C
  4. Quick Check:

    Counts vector size = max + 1 [OK]
Hint: Counts vector must cover all indices up to max element [OK]
Common Mistakes:
  • Not adding +1 to vector size for max element
  • Dereferencing max incorrectly
  • Pushing count instead of element in sorted vector
5. You want to sort an array of integers that includes negative numbers using counting sort in Rust. Which approach correctly adapts counting sort for this case?
hard
A. Shift all numbers by adding the absolute value of the minimum negative number before counting
B. Use the original counting sort without changes; it works with negatives
C. Ignore negative numbers and sort only non-negative ones
D. Convert all numbers to positive by multiplying by -1 before sorting

Solution

  1. Step 1: Understand counting sort limitation

    Counting sort requires non-negative indices for counts, so negatives cause index errors.
  2. Step 2: Shift numbers to non-negative range

    Add absolute value of minimum negative number to all elements to shift them to zero or positive before counting.
  3. Step 3: Sort and then shift back

    After sorting, subtract the shift to restore original values in sorted order.
  4. Final Answer:

    Shift all numbers by adding the absolute value of the minimum negative number before counting -> Option A
  5. Quick Check:

    Shift negatives to non-negative before counting sort [OK]
Hint: Shift negatives to zero or positive before counting sort [OK]
Common Mistakes:
  • Trying to use counting sort directly on negatives
  • Ignoring negative numbers in input
  • Multiplying negatives by -1 changes order incorrectly
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard