Counting Sort Algorithm in DSA Rust - Time & Space Complexity
We want to understand how the time needed to sort numbers using Counting Sort changes as the list grows.
How does the number of steps grow when we have more numbers or a bigger range of values?
Analyze the time complexity of the following code snippet.
fn counting_sort(arr: &mut [usize], max_val: usize) {
let mut count = vec![0; max_val + 1];
for &num in arr.iter() {
count[num] += 1;
}
let mut idx = 0;
for num in 0..=max_val {
for _ in 0..count[num] {
arr[idx] = num;
idx += 1;
}
}
}
This code sorts an array of numbers by counting how many times each number appears, then rebuilding the sorted array.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Two loops: one to count each number, one to rebuild the sorted array.
- How many times: First loop runs once for each element (n times). Second loop runs once for each number in the range (k times), and inside it runs count[num] times, which sums to n.
Counting Sort depends on both the number of elements and the range of numbers.
| Input Size (n) | Range Size (k) | Approx. Operations |
|---|---|---|
| 10 | 5 | About 10 + 5 = 15 |
| 100 | 50 | About 100 + 50 = 150 |
| 1000 | 200 | About 1000 + 200 = 1200 |
Pattern observation: The steps grow roughly with the sum of the number of elements and the range size.
Time Complexity: O(n + k)
This means the time grows linearly with the number of elements plus the range of possible values.
[X] Wrong: "Counting Sort always runs in linear time regardless of the range of numbers."
[OK] Correct: The range size (k) affects the time because we create and loop over a count array of size k, so if k is very large, the time increases.
Understanding how Counting Sort's time depends on both input size and range helps you choose the right sorting method in real problems.
"What if the input array contains negative numbers? How would the time complexity change if we adapt Counting Sort to handle them?"
Practice
Counting Sort Algorithm?Solution
Step 1: Understand Counting Sort principle
Counting sort counts how many times each value appears in the input.Step 2: Use counts to place elements
These counts help place elements directly in the sorted output without comparisons.Final Answer:
Count the occurrences of each element and use counts to place elements in order -> Option BQuick Check:
Counting sort = Counting occurrences and placing [OK]
- Thinking counting sort compares elements
- Confusing counting sort with quicksort or mergesort
- Assuming counting sort works on all data types
Solution
Step 1: Recall Rust vector initialization
In Rust,vec![value; size]creates a vector with repeated values.Step 2: Match syntax to create vector of zeros
vec![0; 5]creates a vector with five zeros, perfect for counting sort.Final Answer:
let counts = vec![0; 5]; -> Option AQuick Check:
vec![0; 5] creates vector of 5 zeros [OK]
- Using parentheses instead of square brackets for vec!
- Confusing array syntax with vector syntax
- Trying to use vec::new with parameters
[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);
}Solution
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.Step 2: Build sorted vector using counts
Push each number count times in order: 1, 2, 2, 3, 3, 4, 8.Final Answer:
[1, 2, 2, 3, 3, 4, 8] -> Option DQuick Check:
Sorted array = [1, 2, 2, 3, 3, 4, 8] [OK]
- Forgetting to repeat elements by their count
- Outputting original array instead of sorted
- Miscounting occurrences of elements
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
}Solution
Step 1: Check vector size for counts
Vector size is*max, but max element index is*max, so size must be*max + 1to include max.Step 2: Fix counts vector size
Changing tovec![0; *max + 1]prevents out-of-bound errors when counting max element.Final Answer:
Changevec![0; *max]tovec![0; *max + 1]-> Option CQuick Check:
Counts vector size = max + 1 [OK]
- Not adding +1 to vector size for max element
- Dereferencing max incorrectly
- Pushing count instead of element in sorted vector
Solution
Step 1: Understand counting sort limitation
Counting sort requires non-negative indices for counts, so negatives cause index errors.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.Step 3: Sort and then shift back
After sorting, subtract the shift to restore original values in sorted order.Final Answer:
Shift all numbers by adding the absolute value of the minimum negative number before counting -> Option AQuick Check:
Shift negatives to non-negative before counting sort [OK]
- Trying to use counting sort directly on negatives
- Ignoring negative numbers in input
- Multiplying negatives by -1 changes order incorrectly
Ready to prove it?
Pass the test and this pattern moves unknown
