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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
! From http://www-h.eng.cam.ac.uk/help/mjg17/f90/mergsort.f90
MODULE Sort

CONTAINS

RECURSIVE SUBROUTINE Module_merge_sort (a, ascend)

  IMPLICIT NONE

  INTEGER, DIMENSION(:), INTENT(INOUT) :: a
  LOGICAL, INTENT(IN), OPTIONAL :: ascend
  LOGICAL :: up

  INTEGER low, high, mid

  ! If 'ascend' parameter is not specified, then default sort to ascending order
  IF (PRESENT(ascend)) THEN
    up = ascend
  ELSE
    up = .TRUE.
  ENDIF

  low=LBOUND(a,1)
  high=UBOUND(a,1)

  IF (low<high) THEN
    mid=(low+high)/2
    CALL Module_merge_sort(a(low:mid), up)
    CALL Module_merge_sort(a(mid+1:high), up)
    a(low:high) = Merge(a(low:mid), a(mid+1:high), up)
  END IF

END SUBROUTINE Module_merge_sort


FUNCTION Merge (a, b, up)

  INTEGER, DIMENSION(:), INTENT(INOUT) :: a, b
  INTEGER, DIMENSION(SIZE(a)+SIZE(b)) :: Merge
  LOGICAL, INTENT(IN) :: up

  INTEGER a_ptr, a_high, a_low
  INTEGER b_ptr, b_high, b_low
  INTEGER c_ptr

  LOGICAL condition

  a_low=LBOUND(a,1)
  a_high=UBOUND(a,1)
  b_low=LBOUND(b,1)
  b_high=UBOUND(b,1)

  a_ptr=a_low
  b_ptr=b_low
  c_ptr=1

  DO WHILE (a_ptr<=a_high .AND. b_ptr<=b_high)

    IF (up) THEN
      condition= (a(a_ptr) <= b(b_ptr))
    ELSE
      condition= (a(a_ptr) >= b(b_ptr))
    END IF

    IF (condition) THEN
      Merge(c_ptr)=a(a_ptr)
      a_ptr=a_ptr+1
    ELSE
      Merge(c_ptr)=b(b_ptr)
      b_ptr=b_ptr+1
    END IF

    c_ptr = c_ptr + 1

  END DO

  IF (a_ptr>a_high) THEN
    Merge(c_ptr:) = b(b_ptr:b_high)
  ELSE
    Merge(c_ptr:) = a(a_ptr:a_high)
  END IF

END FUNCTION Merge

END MODULE Sort




PROGRAM Merge_sort

  USE Sort
  INTEGER, DIMENSION(:), ALLOCATABLE :: array
  INTEGER i, n
  REAL r, time

  PRINT*, "Enter array size:"
  READ(*,*) n

  ALLOCATE( array(n) )

  DO i=1, n
    CALL RANDOM_NUMBER(r)
    array(i)=100 * r
  END DO

  PRINT '(20I3)', array(1:20)
  time = Second()
  CALL Module_merge_sort(array)
  PRINT '("[Sort time = ",F10.3," seconds ]")', Second() - time
  PRINT '(20I3)', array(1:20)
  time = Second()
  CALL Module_merge_sort(array, .FALSE.)
  PRINT '("[Sort time = ",F10.3," seconds ]")', Second() - time
  PRINT '(20I3)', array(1:20)


CONTAINS

REAL FUNCTION Second()

  IMPLICIT NONE

  INTEGER i, timer_count_rate, timer_count_max

  CALL SYSTEM_CLOCK( i, timer_count_rate, timer_count_max )
  Second = REAL(i) / timer_count_rate

END FUNCTION Second


END PROGRAM Merge_sort