The high pivot selection fails badly if there is an ordered set of values.
I have enhanced the code to demonstrate this with real*8 values
program testd
implicit none
real*8, allocatable :: varray(:)
integer :: n_item,ij, ne, np, no,k
logical :: echo_partition = .false.
n_item = 88888000
write (*,11) delta_sec()
Write (*, 10) 'Sort test for size = ',n_item
allocate ( varray(n_item) )
Write (*, 10, advance='NO') 'Initialising'
n_item = size (varray)
call random_number (varray )
write (*,11) delta_sec()
do k = 1,2 ! k=2 tests ordered set
Write (*, 10, advance='NO') 'Sorting'
np = 0
no = 0
call QUICKSORTD (vARRAY, 1, n_item)
write (*,11) delta_sec()
write (*,*) n_item,' items sorted'
write (*,*) np,' partitions'
write (*,*) no,' all shift'
Write (*, 10, advance='NO') 'Checking'
ne = 0
do ij = 1, n_item-1
if ( varray(ij) <= varray(ij+1) ) cycle
write (*,*) ij , ' ' ,varray(ij),varray(ij+1)
ne = ne+1
end do
write (*,11) delta_sec()
write (*,*) ne,' order errors'
end do
10 format (/a,i0)
11 format (2x,f0.4)
contains
RECURSIVE SUBROUTINE QUICKSORTD (DARRAY, LOW, IHIGH)
IMPLICIT NONE
real*8 :: DARRAY(*)
INTEGER LOW, IHIGH, IPIVOT
IF (LOW < IHIGH) THEN
CALL QSRT_PARTITIOND (DARRAY, LOW, IHIGH, IPIVOT)
CALL QUICKSORTD (DARRAY, LOW, IPIVOT - 1)
CALL QUICKSORTD (DARRAY, IPIVOT + 1, IHIGH)
END IF
END SUBROUTINE QUICKSORTD
SUBROUTINE QSRT_PARTITIOND (DARRAY, LOW, HIGH, IPIVOT)
IMPLICIT NONE
real*8 :: DARRAY(*), PIVOT_VALUE, dtemp
INTEGER LOW, HIGH, IPIVOT, I, J, ns, nk
logical :: use_mid_value = .true.
! mid value is much better for sorting an ordered set
if ( use_mid_value ) then
if ( high - low > 1 ) then
ipivot = (low+high) / 2
dtemp = darray(IPIVOT)
darray(IPIVOT) = darray(HIGH)
darray(HIGH) = dtemp
end if
end if
PIVOT_VALUE = DARRAY(HIGH) ! Use the last element as pivot
I = LOW - 1
ns = 0
nk = 0
DO J = LOW, HIGH - 1
IF (DARRAY(J) > PIVOT_VALUE) CYCLE
I = I + 1
if ( i /= j ) then
dtemp = darray(J)
darray(J) = darray(I)
darray(I) = dtemp
ns = ns+1
else
nk = nk+1
end if
END DO
IPIVOT = I + 1
if ( IPIVOT /= HIGH ) then
dtemp = darray(IPIVOT)
darray(IPIVOT) = darray(HIGH)
darray(HIGH) = dtemp
if ( echo_partition ) write (*,*) 'partition', LOW, HIGH, ns, nk
np = np+1
else
if ( echo_partition ) write (*,*) 'no pivot switch', nk, high-low
no = no+1
end if
END SUBROUTINE QSRT_PARTITIOND
real function delta_sec ()
integer*8 :: tick, rate, last_tick = 0
real :: sec
call system_clock ( tick, rate )
sec = real ( tick-last_tick ) / real ( rate )
last_tick = tick
delta_sec = sec
end function delta_sec
end program testd
see 'use_mid_value = .true.' but reduce n_item !