How to resolve the algorithm Sorting algorithms/Radix sort step by step in the Fortran programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Sorting algorithms/Radix sort step by step in the Fortran programming language

Table of Contents

Problem Statement

Sort an integer array with the   radix sort algorithm. The primary purpose is to complete the characterization of sort algorithms task.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Sorting algorithms/Radix sort step by step in the Fortran programming language

Source code in the fortran programming language

      SUBROUTINE VARRADIX(A , Siz)

!
!	No Copyright is exerted due to considerable prior art in the Public Domain.
!       This Fortran version by Peter Kelly ~ peter.kelly@acm.org
!
!	Permission is hereby granted, free of charge, to any person obtaining
!	a copy of this software and associated documentation files (the
!	"Software"), to deal in the Software without restriction, including
!	without limitation the rights to use, copy, modify, merge, publish,
!	distribute, sublicense, and/or sell copies of the Software, and to
!	permit persons to whom the Software is furnished to do so, subject to
!	the following conditions:
!	The above copyright notice and this permission notice shall be
!	included in all copies or substantial portions of the Software.
!	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
!	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
!	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
!	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
!	CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
!	TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
!	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
!          
!    
!     LSD sort with a configurable RADIX, Using a RADIX of 256 performs well, hence I have defaulted it in. It is snarly fast.
!     It could be optimized by merging the two routines but this way gives greater clarity as to what's going on.
      IMPLICIT NONE
!
! PARAMETER definitions
!
      INTEGER , PARAMETER  ::  BASE = 256 ! whatever base you need, just change this
!
! Dummy arguments
!
      INTEGER  ::  Siz
      INTEGER , DIMENSION(Siz)  ::  A
!
! Local variables
!
      INTEGER , ALLOCATABLE , DIMENSION(:)  ::  b
      INTEGER , ALLOCATABLE , DIMENSION(:)  ::  c
      INTEGER  ::  exps
      INTEGER  ::  maxs
!
      ALLOCATE(b(Siz))
      ALLOCATE(c(BASE))
 
      exps = 1
      maxs = MAXVAL(A)
      DO WHILE ( (maxs/exps)>0 )
         CALL XXCOUNTING_SORT(A , Siz , exps , BASE , b , c)
         exps = exps*BASE
      END DO
      deallocate(C)
      deallocate(B)
      RETURN
      CONTAINS
!
!//b is the base you want
!//exp is the value used for the division
      SUBROUTINE XXCOUNTING_SORT(A , Siz , Exps , Base , B , C)
      IMPLICIT NONE
! I used zero based arrays as it made the calcs infinitely easier :)
!
! Dummy arguments
!
      INTEGER  ::  Base
      INTEGER  ::  Exps
      INTEGER  ::  Siz    ! Size
      INTEGER , DIMENSION(0:)  ::  A
      INTEGER , DIMENSION(0:)  ::  B
      INTEGER , DIMENSION(0:)  ::  C
      INTENT (IN) Base , Exps , Siz
      INTENT (INOUT) A , B , C
!
! Local variables
!
      INTEGER  ::  i
      INTEGER  ::  k
!
      C = 0                             ! Init the arrays
      B = 0
!
      DO i = 0 , Siz - 1 , 1
         k = MOD((A(i)/Exps) , Base)    ! Fill Histo
         C(k) = C(k) + 1
      END DO
! 
      DO i = 1 , Base - 1 , 1
         C(i) = C(i) + C(i - 1)         ! Build cumulative Histo
      END DO
! 
      DO i = Siz - 1 , 0 , -1
         k = MOD(A(i)/Exps , Base)      ! Load the Buffer Array in order
         B(C(k) - 1) = A(i)
         C(k) = C(k) - 1
      END DO
!
      DO i = 0 , Siz - 1 , 1              ! Copy across
         A(i) = B(i)
      END DO
      RETURN
      END SUBROUTINE XXCOUNTING_SORT
    END SUBROUTINE Varradix
!*************************************************************************** 
!                            End of LSD sort with any Radix
!***************************************************************************
      MODULE LEASTSIG
      IMPLICIT NONE
!
!	No Copyright is exerted due to considerable prior art in the Public Domain.
!       This Fortran version by Peter Kelly ~ peter.kelly@acm.org
!
!	Permission is hereby granted, free of charge, to any person obtaining
!	a copy of this software and associated documentation files (the
!	"Software"), to deal in the Software without restriction, including
!	without limitation the rights to use, copy, modify, merge, publish,
!	distribute, sublicense, and/or sell copies of the Software, and to
!	permit persons to whom the Software is furnished to do so, subject to
!	the following conditions:
!	The above copyright notice and this permission notice shall be
!	included in all copies or substantial portions of the Software.
!	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
!	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
!	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
!	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
!	CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
!	TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
!	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
!          
!     Implementation of a classic Radix Sort LSD style :)
!     Works well, Integers only but it goes faster than a comparison sort
      CONTAINS
 
! Main Radix Sort sort function
      SUBROUTINE LSDRADIXSORT(A , N)
      IMPLICIT NONE
!
! Dummy arguments
!
      INTEGER  ::  N
      INTEGER , target, DIMENSION(0:N - 1)  ::  A           ! All arrays based off zero, one day I'll fix it
      INTENT (IN) N
      INTENT (INOUT) A
!
! Local variables
! 
      INTEGER , DIMENSION(0:9)  ::  counts
      INTEGER  ::  digitplace
      INTEGER  ::  i
      INTEGER  ::  j
      INTEGER  ::  largestnum
      INTEGER, DIMENSION(0:N - 1)  ::  results 
! 
      digitplace = 1                                        ! Count of the keys
      largestnum = MAXVAL(A)
 
      DO WHILE ( (largestnum/digitplace)>0 )
         counts = 0                                         ! Init the count array
        DO i = 0 , N - 1 , 1
            J = (A(i)/digitplace)
            J = MODULO(j , 10) 
            counts(j) = counts(j) + 1
        END DO

!  Change count(i) so that count(i) now contains actual position of this digit in result()
!  Working similar to the counting sort algorithm
         DO i = 1 , 9 , 1
            counts(i) = counts(i) + counts(i - 1)       ! Build up the prefix sum
         END DO
!
         DO i = N - 1 , 0 , -1                          ! Move from left to right
            j = (A(i)/digitplace)
            j = MODULO(j, 10)
            results(counts(j) - 1) = A(i)               ! Need to subtract one as we are zero based but prefix sum is 1 based
            counts(j) = counts(j) - 1
         END DO
!
         DO i = 0 , N - 1 , 1                           ! Copy the semi-sorted data into the input
           A(i) = results(i)
         END DO
!
         digitplace = digitplace*10
      END DO                                             ! While loop
      RETURN
      END SUBROUTINE LSDRADIXSORT
      END MODULE LEASTSIG
!*************************************************************************** 
!                            End of Classic LSD sort with Radix 10
!***************************************************************************
!Superfast FORTRAN LSD sort
! Dataset is input array, Scratch is working array
!
      SUBROUTINE FASTLSDRAD(Dataset , Scratch , Dsize)
!
!	No Copyright is exerted due to considerable prior art in the Public Domain.
!       This Fortran version by Peter Kelly ~ peter.kelly@acm.org
!
!	Permission is hereby granted, free of charge, to any person obtaining
!	a copy of this software and associated documentation files (the
!	"Software"), to deal in the Software without restriction, including
!	without limitation the rights to use, copy, modify, merge, publish,
!	distribute, sublicense, and/or sell copies of the Software, and to
!	permit persons to whom the Software is furnished to do so, subject to
!	the following conditions:
!	The above copyright notice and this permission notice shall be
!	included in all copies or substantial portions of the Software.
!	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
!	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
!	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
!	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
!	CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
!	TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
!	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
!          
!     This LSD sort is optimized to a base 16,Radix 256 sort which is about as fast as LSD gets. As well as a fast
!     algorithm, it has great cache coherency so performs exceptionally on large data sets,
!     I have optimized out all the divide and modulus functions and replaced them with bit shifts for speed.
!     A further speed optimization is obtained by using pointers to the DATA and TEMP arrays and swapping them each pass of
!     the LSB calculation. In FORTRAN this is a bit clunky but much faster than copying data back and forth between arrays.
!
!     All arrays are zero based as this makes the indexing calculations straightforward without the need for
!     subsequent adds and subtracts to track the correct index
!         .
      IMPLICIT NONE
!
! Dummy arguments
!
      INTEGER  ::  Dsize
      INTEGER , TARGET , DIMENSION(0:Dsize - 1)  ::  Scratch    ! Declared as TARGET as we will manipulate with pointers
      INTEGER , TARGET , DIMENSION(0:Dsize - 1)  ::  Dataset
      INTENT (IN) Dsize
      INTENT (INOUT) Scratch , Dataset
!
! Local variables
!
      INTEGER , POINTER , DIMENSION(:)  ::  a                   ! The pointer to the data
      INTEGER , POINTER , DIMENSION(:)  ::  b                   ! The pointer to the buffer
      INTEGER  ::  i
      INTEGER  ::  j
      INTEGER  ::  m
      INTEGER , DIMENSION(0:255,0:3)  ::  stats_table
      INTEGER  ::  n
      LOGICAL  ::  swap
      INTEGER  ::  u
      
!
      stats_table = 0                                           !   index matrix
      swap = .TRUE.                                             !   For swapping pointers
!
      a => Dataset
      b => Scratch
!
      DO i = 0 , Dsize - 1 , 1                                  ! generate histograms
         u = a(i)
         DO j = 0 , 3 , 1
            n = IAND(u , z'FF')
            u = SHIFTR(u , 8)
            stats_table(n,j) = stats_table(n,j) + 1
         END DO
      END DO
!
      DO i = 0 , 3 , 1                                          ! convert to indices
         m = 0
         DO j = 0 , 255 , 1
            n = stats_table(j , i)
            stats_table(j , i) = m
            m = m + n
         END DO
      END DO
!
      DO j = 0 , 3 , 1                                          ! Radix Sort, sort by LSB
         DO i = 0 , Dsize - 1 , 1
            u = a(i)
            m = IAND(SHIFTR(u,SHIFTL(j,3)) , z'FF')             ! Eliminate the MOD 16 and div with shifts
            b(stats_table(m,j)) = u                             ! Push the data into the buffer
            stats_table(m,j) = stats_table(m,j) + 1
         END DO
!
!        Instead of copying back from the temp values swap the array pointers
!
         IF( swap )THEN
            a => Scratch                                        ! A now points to the b buffer
            b => Dataset                                        ! B now is the data set
         ELSE
            a => Dataset
            b => Scratch
         END IF
         swap = .NOT.swap                                       ! Set to swap back and forth every pass
      END DO
 !
      RETURN
      END SUBROUTINE FASTLSDRAD
!*************************************************************************** 
!                            End of Superfast LSD sort
!***************************************************************************
*=======================================================================
* RSORT - sort a list of integers by the Radix Sort algorithm
* Public domain.  This program may be used by any person for any purpose.
* Origin:  Herman Hollerith, 1887
*
*___Name____Type______In/Out____Description_____________________________
*   IX(N)   Integer   Both      Array to be sorted in increasing order
*   IW(N)   Integer   Neither   Workspace
*   N       Integer   In        Length of array
*
* ASSUMPTIONS:  Bits in an INTEGER is an even number.
*               Integers are represented by twos complement.
*
* NOTE THAT:  Radix sorting has an advantage when the input is known 
*             to be less than some value, so that only a few bits need 
*             to be compared.  This routine looks at all the bits, 
*             and is thus slower than Quicksort.
*=======================================================================
      SUBROUTINE RSORT (IX, IW, N)      
       IMPLICIT NONE
       INTEGER IX, IW, N
       DIMENSION IX(N), IW(N)

       INTEGER I,                        ! count bits
     $         ILIM,                     ! bits in an integer
     $         J,                        ! count array elements
     $         P1OLD, P0OLD, P1, P0,     ! indices to ones and zeros
     $         SWAP
       LOGICAL ODD                       ! even or odd bit position

*      IF (N < 2) RETURN      ! validate
*
        ILIM = Bit_size(i)    !Get the fixed number of bits
*=======================================================================
* Alternate between putting data into IW and into IX
*=======================================================================
       P1 = N+1
       P0 = N                ! read from 1, N on first pass thru
       ODD = .FALSE.
       DO I = 0, ILIM-2
         P1OLD = P1
         P0OLD = P0         ! save the value from previous bit
         P1 = N+1
         P0 = 0                 ! start a fresh count for next bit

         IF (ODD) THEN
           DO J = 1, P0OLD, +1             ! copy data from the zeros
             IF ( BTEST(IW(J), I) ) THEN
               P1 = P1 - 1
               IX(P1) = IW(J)
             ELSE
               P0 = P0 + 1
               IX(P0) = IW(J)
             END IF
           END DO
           DO J = N, P1OLD, -1             ! copy data from the ones
             IF ( BTEST(IW(J), I) ) THEN
               P1 = P1 - 1
               IX(P1) = IW(J)
             ELSE
               P0 = P0 + 1
              IX(P0) = IW(J)
             END IF
           END DO
          
         ELSE 
           DO J = 1, P0OLD, +1             ! copy data from the zeros
             IF ( BTEST(IX(J), I) ) THEN
               P1 = P1 - 1
               IW(P1) = IX(J)
              ELSE
               P0 = P0 + 1
               IW(P0) = IX(J)
             END IF
           END DO
           DO J = N, P1OLD, -1            ! copy data from the ones
             IF ( BTEST(IX(J), I) ) THEN
               P1 = P1 - 1
               IW(P1) = IX(J)
             ELSE
               P0 = P0 + 1
               IW(P0) = IX(J)
             END IF
          END DO
         END IF  ! even or odd i
        
         ODD = .NOT. ODD
       END DO  ! next i

*=======================================================================
*        the sign bit
*=======================================================================
       P1OLD = P1
       P0OLD = P0
       P1 = N+1
       P0 = 0 

*          if sign bit is set, send to the zero end
       DO J = 1, P0OLD, +1
         IF ( BTEST(IW(J), ILIM-1) ) THEN 
           P0 = P0 + 1
           IX(P0) = IW(J)
         ELSE
           P1 = P1 - 1
           IX(P1) = IW(J)
         END IF
       END DO          
       DO J = N, P1OLD, -1
         IF ( BTEST(IW(J), ILIM-1) ) THEN
           P0 = P0 + 1
           IX(P0) = IW(J)
         ELSE
           P1 = P1 - 1
           IX(P1) = IW(J)
         END IF
       END DO
          
*=======================================================================
*       Reverse the order of the greater value partition
*=======================================================================
       P1OLD = P1
       DO J = N, (P1OLD+N)/2+1, -1
         SWAP = IX(J)
         IX(J) = IX(P1)
         IX(P1) = SWAP
         P1 = P1 + 1
       END DO
       RETURN
      END ! of RSORT


***********************************************************************
*         test program
***********************************************************************
      PROGRAM t_sort
       IMPLICIT NONE
       INTEGER I, N
       PARAMETER (N = 11)
       INTEGER IX(N), IW(N)
       LOGICAL OK
       
       DATA IX / 2, 24, 45, 0, 66, 75, 170, -802, -90, 1066, 666 /
       
       PRINT *, 'before: ', IX
       CALL RSORT (IX, IW, N)
       PRINT *, 'after: ', IX
       
*              compare
       OK = .TRUE.
       DO I = 1, N-1
         IF (IX(I) > IX(I+1)) OK = .FALSE.
       END DO
       IF (OK) THEN
         PRINT *, 't_sort: successful test'
       ELSE
         PRINT *, 't_sort: failure!'
       END IF
      END ! of test program


  

You may also check:How to resolve the algorithm Greatest common divisor step by step in the gnuplot programming language
You may also check:How to resolve the algorithm Queue/Usage step by step in the VBA programming language
You may also check:How to resolve the algorithm Logical operations step by step in the Aime programming language
You may also check:How to resolve the algorithm MD5 step by step in the Slate programming language
You may also check:How to resolve the algorithm Find the missing permutation step by step in the PowerShell programming language