Sorting algorithms/Counting sort

From Rosetta Code
Task
Sorting algorithms/Counting sort
You are encouraged to solve this task according to the task description, using any language you may know.
This page uses content from Wikipedia. The original article was at Sorting algorithms/Counting sort. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)

Implement the Counting sort. This is a way of sorting integers when the minimum and maximum value are known.

Pseudocode:

countingSort(array, min, max):
  count: array of (max - min + 1) elements
  initialize count with 0s
  foreach number in array:
    count[number - min] := count[number - min] + 1
  end foreach
  z := 0
  for i from min to max:
    while ( count[i - min] > 0 )
      array[z] := i
      z := z + 1
      count[i - min] := count[i - min] - 1
    end while
  end for
end countingSort

The min and max can be computed apart, or be known a priori.

Note: we know that, given an array of integers, its maximum and minimum values can be always found; but if we imagine the worst case for an array of 32 bit integers, we see that in order to hold the counts, we need an array of 232 elements, i.e. we need, to hold a count value up to 232-1, more or less 16 Gbytes. So the counting sort is more practical when the range is (very) limited and minimum and maximum values are known a priori. (Anyway sparse arrays may limit the impact of the memory usage)

C

<lang c>#include <stdio.h>

  1. include <stdlib.h>

void counting_sort_mm(int *array, int n, int min, int max) {

 int i, j, z;
 int range = max - min + 1;
 int *count = malloc(range * sizeof(*array));
 for(i = 0; i < range; i++) count[i] = 0;
 for(i = 0; i < n; i++) count[ array[i] - min ]++;
 for(i = min, z = 0; i <= max; i++) {
   for(j = 0; j < count[i - min]; j++) {
     array[z++] = i;
   }
 } 
 free(count);

}

void counting_sort(int *array, int n) {

 int i, min, max;
 
 min = max = array[0];
 for(i=1; i < n; i++) {
   if ( array[i] < min ) {
     min = array[i];
   } else if ( array[i] > max ) {
     max = array[i];
   }
 }

}</lang>

Testing (we suppose the oldest human being is less than 140 years old).

<lang c>#define N 100

  1. define MAX_AGE 140

int main() {

 int ages[N], i;
 for(i=0; i < N; i++) ages[i] = rand()%MAX_AGE;
 counting_sort_mm(ages, N, 0, MAX_AGE);
 for(i=0; i < N; i++) printf("%d\n", ages[i]);
 return EXIT_SUCCESS;

}</lang>

E

Straightforward implementation, no particularly interesting characteristics.

<lang e>def countingSort(array, min, max) {

   def counts := ([0] * (max - min + 1)).diverge()
   for elem in array {
       counts[elem - min] += 1
   }
   var i := -1
   for offset => count in counts {
       def elem := min + offset
       for _ in 1..count {
           array[i += 1] := elem
       }
   }

}</lang>

<lang e>? def arr := [34,6,8,7,4,3,56,7,8,4,3,5,7,8,6,4,4,67,9,0,0,76,467,453,34,435,37,4,34,234,435,3,2,7,4,634,534,735,5,4,6,78,4].diverge()

  1. value: [34, 6, 8, 7, 4, 3, 56, 7, 8, 4, 3, 5, 7, 8, 6, 4, 4, 67, 9, 0, 0, 76, 467, 453, 34, 435, 37, 4, 34, 234, 435, 3, 2, 7, 4, 634, 534, 735, 5, 4, 6, 78, 4].diverge()

? countingSort(arr, 0, 735) ? arr

  1. value: [0, 0, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 34, 34, 34, 37, 56, 67, 76, 78, 234, 435, 435, 453, 467, 534, 634, 735].diverge()</lang>

Fortran

Works with: Fortran version 95 and later

<lang fortran>module CountingSort

 implicit none
 interface counting_sort
    module procedure counting_sort_mm, counting_sort_a
 end interface

contains

 subroutine counting_sort_a(array)
   integer, dimension(:), intent(inout) :: array
   call counting_sort_mm(array, minval(array), maxval(array))
 end subroutine counting_sort_a
 subroutine counting_sort_mm(array, tmin, tmax)
   integer, dimension(:), intent(inout) :: array
   integer, intent(in) :: tmin, tmax
   integer, dimension(tmin:tmax) :: cnt
   integer :: i, z
   forall(i=tmin:tmax)
      cnt(i) = count(array == i)
   end forall
   z = 1
   do i = tmin, tmax
      do while ( cnt(i) > 0 )
         array(z) = i
         z = z + 1
         cnt(i) = cnt(i) - 1
      end do
   end do
 end subroutine counting_sort_mm

end module CountingSort</lang>

Testing:

<lang fortran>program test

 use CountingSort
 implicit none
 integer, parameter :: n = 100, max_age = 140
 real, dimension(n) :: t
 integer, dimension(n) :: ages
 call random_number(t)
 ages = floor(t * max_age)
 call counting_sort(ages, 0, max_age)
 write(*,'(I4)') ages

end program test</lang>

Java

Works with: Java version 1.5+

<lang java5>public static void countingSort(int[] array, int min, int max){ int[] count= new int[max - min + 1]; for(int number : array){ count[number - min]++; } int z= 0; for(int i= min;i <= max;i++){ while(count[i - min] > 0){ array[z]= i; z++; count[i - min]--; } } }</lang>

Modula-3

<lang modula3>MODULE Counting EXPORTS Main;

IMPORT IO, Fmt;

VAR test := ARRAY [1..8] OF INTEGER {80, 10, 40, 60, 50, 30, 20, 70};

PROCEDURE Sort(VAR a: ARRAY OF INTEGER; min, max: INTEGER) =

 VAR range := max - min + 1;
     count := NEW(REF ARRAY OF INTEGER, range);
     z := 0;
 BEGIN
   FOR i := FIRST(count^) TO LAST(count^) DO
     count[i] := 0;
   END;
   FOR i := FIRST(a) TO LAST(a) DO
     INC(count[a[i] - min]);
   END;
   FOR i := min TO max DO
     WHILE (count[i - min] > 0) DO
       a[z] := i;
       INC(z);
       DEC(count[i - min]);
     END;
   END;
 END Sort;

BEGIN

 IO.Put("Unsorted: ");
 FOR i := FIRST(test) TO LAST(test) DO
   IO.Put(Fmt.Int(test[i]) & " ");
 END;
 IO.Put("\n");
 Sort(test, 10, 80);
 IO.Put("Sorted: ");
 FOR i := FIRST(test) TO LAST(test) DO
   IO.Put(Fmt.Int(test[i]) & " ");
 END;
 IO.Put("\n");

END Counting.</lang> Output:

Unsorted: 80 10 40 60 50 30 20 70 
Sorted: 10 20 30 40 50 60 70 80 

Octave

This implements the same algorithm but in a more compact way (using the same loop to count and to update the sorted vector). This implementation is elegant (and possible since the sort is not done "in place"), but not so efficient on machines that can't parallelize some operations (the vector arr is scanned for every value between minval and maxval) <lang octave>function r = counting_sort(arr, minval, maxval)

 r = arr;
 z = 1;
 for i = minval:maxval
   cnt = sum(arr == i);
   while( cnt-- > 0 )
     r(z++) = i;
   endwhile
 endfor

endfunction </lang>

Testing:

<lang octave>ages = unidrnd(140, 100, 1); sorted = counting_sort(ages, 0, 140); disp(sorted);</lang>

Perl

<lang perl>#! /usr/bin/perl use strict;

sub counting_sort {

   my ($a, $min, $max) = @_;
   
   my @cnt = ();
   
   my $range = $max - $min + 1;
   foreach my $i ($min .. $max) { $cnt[$i] = 0 }
   foreach my $n (@$a) { $cnt[$n]++ }
   my $z = 0;
   foreach my $i ($min .. $max) {

while( $cnt[$i]-- > 0) { ${$a}[$z] = $i; $z++; }

   }

}</lang>

Testing:

<lang perl>my @ages = (); push @ages, int(rand(140)) while(scalar(@ages) < 100);

counting_sort(\@ages, 0, 140); print join("\n", @ages) . "\n";</lang>

PHP

<lang php><?php

function counting_sort($arr, $min, $max) {

 $count = array();
 for($i = $min; $i <= $max; $i++)
 {
   $count[$i] = 0;
 }
 foreach($arr as $number)
 {
   $count[$number]++; 
 }
 $z = 0;
 for($i = $min; $i <= $max; $i++) {
   while( $count[$i]-- > 0 ) {
     $arr[$z++] = $i;
   }
 }

}</lang>

Testing:

<lang php>$ages = array(); for($i=0; $i < 100; $i++) {

 array_push($ages, rand(0, 140));

} counting_sort(&$ages, 0, 140);

for($i=0; $i < 100; $i++) {

 echo $ages[$i] . "\n";

} ?></lang>

Smalltalk

Works with: GNU Smalltalk

<lang smalltalk>OrderedCollection extend [

   countingSortWithMin: min andMax: max [

|oc z| oc := OrderedCollection new. 1 to: (max - min + 1) do: [ :n| oc add: 0 ]. self do: [ :v | oc at: (v - min + 1) put: ( (oc at: (v - min + 1)) + 1) ]. z := 1. min to: max do: [ :i | 1 to: (oc at: (i - min + 1)) do: [ :k | self at: z put: i. z := z + 1. ] ]

   ]

].</lang>

Testing:

<lang smalltalk>|ages|

ages := OrderedCollection new.

1 to: 100 do: [ :n |

   ages add: (Random between: 0 and: 140)

].

ages countingSortWithMin: 0 andMax: 140. ages printNl.</lang>

Tcl

Works with: Tcl version 8.5

<lang tcl>proc countingsort {a {min ""} {max ""}} {

   # If either of min or max weren't given, compute them now
   if {$min eq ""} {
       set min [::tcl::mathfunc::min $a]
   }
   if {$max eq ""} {
       set max [::tcl::mathfunc::max $a]
   }
   # Make the "array" of counters
   set count [lrepeat [expr {$max - $min + 1}] 0]
   # Count the values in the input list
   foreach n $a {
       set idx [expr {$n - $min}]
       lincr count $idx
   }
   # Build the output list
   set z 0
   for {set i $min} {$i <= $max} {incr i} {
       set idx [expr {$i - $min}]
       while {[lindex $count $idx] > 0} {
           lset a $z $i
           incr z
           lincr count $idx -1
       }
   }
   return $a

}

  1. Helper that will increment an existing element of a list

proc lincr {listname idx {value 1}} {

   upvar 1 $listname list
   lset list $idx [expr {[lindex $list $idx] + $value}]

}

  1. Demo code

for {set i 0} {$i < 50} {incr i} {lappend a [expr {1+ int(rand()*10)}]} puts $a puts [countingsort $a]</lang>

9 7 10 2 9 7 4 3 10 2 7 10 2 1 3 8 7 3 9 5 8 5 1 6 3 7 5 4 6 9 9 6 6 10 2 4 5 2 8 2 2 5 2 9 3 3 5 7 8 4
1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 5 5 5 5 5 5 6 6 6 6 7 7 7 7 7 7 8 8 8 8 9 9 9 9 9 9 10 10 10 10