Counting Sort Algorithm
1. Algorithm Explanation
Counting Sort is a non-comparative integer sorting algorithm. It assumes the input consists of elements in a known, limited range [0…K]. It works by:
- Counting the occurrences of each distinct element in the input array into a "count" array of size K + 1.
- Transforming the count array so that each position contains the cumulative count of elements ≤ that index.
- Iterating the original array in reverse order, placing each element in its correct sorted position in an output array, and decrementing the corresponding count.
Time Complexity
- O(n + K), where n = number of elements, K = range of input values.
Space Complexity
- O(n + K): additional output array of size n plus count array of size K + 1.
2. Easy Problems
2.1. Sort an Array of Non-negative Integers
Given an array of non-negative integers, sort it in non-decreasing order.
#include <iostream>
#include <vector>
using namespace std;
void countingSort(vector<int>& A, int K) {
int n = A.size();
vector<int> count(K+1, 0), output(n);
for (int x : A) count[x]++;
for (int i = 1; i <= K; i++) count[i] += count[i-1];
for (int i = n-1; i >= 0; i--) {
output[count[A[i]] - 1] = A[i];
count[A[i]]--;
}
A = output;
}
int main() {
vector<int> A = {4, 2, 2, 8, 3, 3, 1};
countingSort(A, 8);
for (int x : A) cout << x << " ";
return 0;
}
2.2. Sort Characters in a String
Given a string of lowercase letters, return the sorted string.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string countingSortString(const string& s) {
int K = 25; // 'a' to 'z'
vector<int> count(K+1, 0);
for (char c : s) count[c - 'a']++;
string out;
out.reserve(s.size());
for (int i = 0; i <= K; i++) {
out.append(count[i], char('a' + i));
}
return out;
}
int main() {
string s = "dbcaab";
cout << countingSortString(s);
return 0;
}
3. Intermediate Problems
3.1. Sort Signed Integers (including negatives)
Extend Counting Sort to handle negative values by offsetting.
#include <iostream>
#include <vector>
using namespace std;
void countingSortSigned(vector<int>& A) {
int n = A.size();
int minV = *min_element(A.begin(), A.end());
int maxV = *max_element(A.begin(), A.end());
int range = maxV - minV + 1;
vector<int> count(range, 0), output(n);
for (int x : A) count[x - minV]++;
for (int i = 1; i < range; i++) count[i] += count[i-1];
for (int i = n-1; i >= 0; i--) {
output[count[A[i] - minV] - 1] = A[i];
count[A[i] - minV]--;
}
A = output;
}
int main() {
vector<int> A = {-5, -10, 0, -3, 8, 5, -1, 10};
countingSortSigned(A);
for (int x : A) cout << x << " ";
return 0;
}
3.2. Counting Sort as Subroutine in Radix Sort
Use Counting Sort to sort numbers by each digit (LSD Radix Sort).
#include <iostream>
#include <vector>
using namespace std;
void countingSortByDigit(vector<int>& A, int exp) {
int n = A.size();
vector<int> count(10, 0), output(n);
for (int x : A) count[(x / exp) % 10]++;
for (int i = 1; i < 10; i++) count[i] += count[i-1];
for (int i = n-1; i >= 0; i--) {
int idx = (A[i] / exp) % 10;
output[count[idx] - 1] = A[i];
count[idx]--;
}
A = output;
}
void radixSort(vector<int>& A) {
int maxV = *max_element(A.begin(), A.end());
for (int exp = 1; maxV / exp > 0; exp *= 10) {
countingSortByDigit(A, exp);
}
}
int main() {
vector<int> A = {170, 45, 75, 90, 802, 24, 2, 66};
radixSort(A);
for (int x : A) cout << x << " ";
return 0;
}
4. Hard Problem
4.1. Sorting Queries of Frequencies (Top-K Frequent Elements)
Given an array, find the k most frequent elements. We can use Counting Sort on frequencies when the maximum frequency is bounded by n.
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
// Returns k most frequent elements
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> freq;
for (int x : nums) freq[x]++;
int n = nums.size();
// bucket[i] contains all numbers with frequency i
vector<vector<int>> bucket(n+1);
for (auto &p : freq) {
bucket[p.second].push_back(p.first);
}
vector<int> res;
for (int i = n; i >= 1 && res.size() < k; --i) {
for (int x : bucket[i]) {
res.push_back(x);
if (res.size() == k) break;
}
}
return res;
}
int main() {
vector<int> nums = {1,1,1,2,2,3};
int k = 2;
vector<int> ans = topKFrequent(nums, k);
for (int x : ans) cout << x << " ";
return 0;
}