Quick Info

Category: Sorting
Time Complexity: O(n + k)
Space Complexity: O(k)
Stable: Yes
In-Place: No

Counting Sort

Description

Counting Sort is a non-comparison based sorting algorithm that works by counting the number of occurrences of each element in the array. It operates by creating an auxiliary array to store the frequencies of each element, and then using this information to place elements in their correct sorted positions.

History

Counting Sort Concept

Counting Sort emerged in the early days of computer science, during the 1950s, when researchers were exploring non-comparison based sorting methods. Unlike many other sorting algorithms that are named after their inventors, Counting Sort is named after its process of counting elements. The algorithm gained prominence as a subroutine in Radix Sort, where it's used to sort numbers digit by digit. Its ability to sort in linear time made it particularly valuable in specific applications where the range of input values is known and reasonably small compared to the number of items to be sorted. The algorithm has found widespread use in various applications, from sorting postal codes to computer graphics rendering pipelines where elements need to be sorted by depth (z-index).

How It Works

  1. Count Frequencies:
    • Create a count array of size k (range of input)
    • Count occurrences of each element
  2. Calculate Cumulative Count:
    • Modify count array to store actual positions
    • Each element shows final position of elements
  3. Build Output Array:
    • Place each element in its correct position
    • Decrement count for each placement

Visualization

Click Start to begin visualization

Implementation


def counting_sort(arr):
    # Find the range of input array
    max_val = max(arr)
    min_val = min(arr)
    range_val = max_val - min_val + 1
    
    # Initialize count array and output array
    count = [0] * range_val
    output = [0] * len(arr)
    
    # Store count of each element
    for i in arr:
        count[i - min_val] += 1
    
    # Modify count array to store actual positions
    for i in range(1, len(count)):
        count[i] += count[i - 1]
    
    # Build output array
    for i in range(len(arr) - 1, -1, -1):
        output[count[arr[i] - min_val] - 1] = arr[i]
        count[arr[i] - min_val] -= 1
    
    # Copy output array to input array
    for i in range(len(arr)):
        arr[i] = output[i]
    
    return arr
                                        

void countingSort(vector& arr) {
    // Find range of array elements
    int max_val = *max_element(arr.begin(), arr.end());
    int min_val = *min_element(arr.begin(), arr.end());
    int range = max_val - min_val + 1;
    
    // Create count array and output array
    vector count(range), output(arr.size());
    
    // Store count of each element
    for(int i = 0; i < arr.size(); i++)
        count[arr[i] - min_val]++;
        
    // Modify count array to store actual positions
    for(int i = 1; i < count.size(); i++)
        count[i] += count[i-1];
        
    // Build output array
    for(int i = arr.size()-1; i >= 0; i--) {
        output[count[arr[i] - min_val] - 1] = arr[i];
        count[arr[i] - min_val]--;
    }
    
    // Copy output array to input array
    for(int i = 0; i < arr.size(); i++)
        arr[i] = output[i];
}

// Example usage
int main() {
    vector arr = {64, 34, 25, 12, 22, 11, 90};
    cout << "Original array: ";
    for(int num : arr) cout << num << " ";
    
    countingSort(arr);
    
    cout << "\nSorted array: ";
    for(int num : arr) cout << num << " ";
    return 0;
}
                                        

public class CountingSort
{
    public static void Sort(int[] arr)
    {
        // Find range of array elements
        int maxVal = arr.Max();
        int minVal = arr.Min();
        int range = maxVal - minVal + 1;
        
        // Create count array and output array
        int[] count = new int[range];
        int[] output = new int[arr.Length];
        
        // Store count of each element
        for(int i = 0; i < arr.Length; i++)
            count[arr[i] - minVal]++;
            
        // Modify count array to store actual positions
        for(int i = 1; i < count.Length; i++)
            count[i] += count[i - 1];
            
        // Build output array
        for(int i = arr.Length - 1; i >= 0; i--)
        {
            output[count[arr[i] - minVal] - 1] = arr[i];
            count[arr[i] - minVal]--;
        }
        
        // Copy output array to input array
        for(int i = 0; i < arr.Length; i++)
            arr[i] = output[i];
    }
    
    // Example usage
    public static void Main(string[] args)
    {
        int[] arr = { 64, 34, 25, 12, 22, 11, 90 };
        Console.WriteLine("Original array: " + string.Join(" ", arr));
        
        Sort(arr);
        
        Console.WriteLine("Sorted array: " + string.Join(" ", arr));
    }
}
                                        

Applications

  • Sorting integers with known range
  • Sorting postal codes
  • Sorting strings (as part of radix sort)
  • Computer graphics (sorting by z-index)
  • DNA sequence analysis

Advantages and Disadvantages

Advantages

  • Linear time complexity O(n + k)
  • Stable sorting algorithm
  • Efficient for integers with known range
  • Good as a subroutine in radix sort

Disadvantages

  • Not in-place sorting
  • Requires extra space O(k)
  • Only works with discrete values
  • Not efficient when range k is much larger than n

Complexity Analysis

Case Time Complexity Description
Best Case Ω(n + k) Always performs same operations regardless of input arrangement
Average Case Θ(n + k) Requires two passes through array of size n and one through count array of size k
Worst Case O(n + k) Same as other cases due to non-comparative nature
Space Complexity O(k) Requires count array of size k and output array of size n

Notes:

  • n - Number of elements in the input array
  • k - Range of input (max - min + 1)
  • Linear time complexity when k = O(n)
  • Not efficient when k >> n (range much larger than array size)
  • Performance independent of input distribution