-
Notifications
You must be signed in to change notification settings - Fork 140
/
Copy pathquicksort.F90
94 lines (80 loc) · 3.66 KB
/
quicksort.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
!***********************************************************************
!* GNU Lesser General Public License
!*
!* This file is part of the GFDL Flexible Modeling System (FMS).
!*
!* FMS is free software: you can redistribute it and/or modify it under
!* the terms of the GNU Lesser General Public License as published by
!* the Free Software Foundation, either version 3 of the License, or (at
!* your option) any later version.
!*
!* FMS is distributed in the hope that it will be useful, but WITHOUT
!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
!* for more details.
!*
!* You should have received a copy of the GNU Lesser General Public
!* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
!***********************************************************************
!> @cond
#undef _TYP
#define _TYP integer
!> @endcond
!> @defgroup quicksort quicksort
!> @ingroup drifters
!> @brief Fortran implementation of quicksort to be used in @ref drifters_core
!!
!> @author Magnus Lie Hetland
!> Create array partitions for quicksort
function qksrt_partition(n, list, start, end) result(top)
implicit none
integer, intent(in) :: n
_TYP, intent(inout) :: list(n)
integer, intent(in) :: start, end
integer pivot, bottom, top
logical done
pivot = list(end) ! Partition around the last value
bottom = start-1 ! Start outside the area to be partitioned
top = end ! Ditto
done = .false.
do while (.not. done) ! Until all elements are partitioned...
do while (.not. done) ! Until we find an out of place element...
bottom = bottom+1 ! ... move the bottom up.
if(bottom == top) then ! If we hit the top...
done = .true. ! ... we are done.
exit
endif
if(list(bottom) > pivot) then ! Is the bottom out of place?
list(top) = list(bottom) ! Then put it at the top...
exit ! ... and start searching from the top.
endif
enddo
do while (.not. done) ! Until we find an out of place element...
top = top-1 ! ... move the top down.
if(top == bottom) then ! If we hit the bottom...
done = .true. ! ... we are done.
exit
endif
if(list(top) < pivot) then ! Is the top out of place?
list(bottom) = list(top) ! Then put it at the bottom...
exit ! ...and start searching from the bottom.
endif
enddo
enddo
list(top) = pivot ! Put the pivot in its place.
! Return the split point
end function qksrt_partition
!> quicksort a given list
recursive subroutine qksrt_quicksort(n, list, start, end)
implicit none
integer, intent(in) :: n
_TYP, intent(inout) :: list(n)
integer, intent(in) :: start, end
integer :: split, qksrt_partition
external :: qksrt_partition
if(start < end) then ! If there are two or more elements...
split = qksrt_partition(n, list, start, end) ! ... partition the sublist...
call qksrt_quicksort(n, list, start, split-1) ! ... and sort both halves.
call qksrt_quicksort(n, list, split+1, end)
endif
end subroutine qksrt_quicksort