Some
Advanced Features of Procedures
Recursion
•
Recursive
Calls
–
A procedure can call itself (Self
Recursion)
–
A can call B, B calls C, etc, Z calls A (Mutual Recursion)
•
Powerful
Abstraction
–
Many functions are recursive in nature
–
Factorial, Fibonacci, etc.
fact(0) = 1
fact(n+1) = (n+1) * fact(n)
fib(0) = 1
fib(1) = 1
fib(n+2) = fib(n+1) + fib(n)
• Such functions can be
directly encoded
Complex control Flow
• Recursive functions abstracts out
complex control flow
– Different instance of the same
procedure exists at a time
– Termination and resumption of different
instances correctly
– Last called is exited first ( Last In
First Out LIFO)
– Use of stack data structure (stack
overflow)
– A lot of overhead in implementation
Factorial Example
Program fact
Implicit none
integer:: N, z
read *, N
call fct(N, z)
print *, z
contains
recursive subroutine fct(M, y)
implicit none
integer, intent(in):: M
integer, intent(out):: y
if (M >= 1) then
call fct(M - 1, y)
y = M * y
else
y = 1
endif
end subroutine
end program
Recursive Function
Program fact
implicit none
integer:: N, z
read *, N
z = fct(N)
print *, z
contains
recursive integer function fct(M)
result(answer)
implicit none
integer:: M, answer
if (M /= 0) then
answer = M * fct(M - 1)
else
answer = 1
endif
end function
end program
Fibonacci Numbers
Program fibonacci
implicit none
integer:: N, z
read *, N
call fib(N, z)
print *, z
contains
recursive subroutine fib(M, y)
implicit none
integer, intent(in):: M
integer, intent(out):: y
integer:: y1, y2
if (M > 1) then
call fib(M - 1, y1)
call fib(M - 1, y2)
y = y1 + y2
else
y = 1
endif
end subroutine
end program
Tower of Hanoi Problem
• Initial Configuration
Final Configuration
Rules
• Only one disc can be moved at a time
• bigger disc never placed over a smaller
one
• only one temporary pole
• How to solve the problem?
Divide and Conquer
• Reduce the problem size! How?
• Consider the following situation:
Sub problems
• How to transfer smaller (n-1) discs
from initial pole to temporary pole?
• How to transfer smaller (n-1) discs to
the final pole from temporary pole?
• These two problems are similar but with
the problem size reduced and the initial and final poles being different
• How to solve the sub problems?
– Reduce further down (recursion)
• When (n-1) = 1, the problem becomes
trivial
Sub problems
Algorithm hanoi_tower (ndisks,
init_pole, spare_pole,
fin_pole)
1. If
(ndisks > 0) then
1.1
hanoi_tower(ndisks - 1, init_pole, fin_pole,
spare_pole)
1.2
transfer_disk(init_pole, fin_pole)
1.3
hanoi_tower(ndisks - 1, spare_pole, init_pole,
fin_pole)
end
end
• When the first argument is 0, no action, only empty
recursive calls
• Simplify by removing the recursive calls for the case ndiscs
= 1
Fortran Solution
• requires modeling the problem domain
• Need software models for all real
objects
• Discs, poles, movements etc.
• Discs as numbers, poles as stacks,
movements as pushes and pops
Quick Sort
•
quick
sort is another sorting algorithm which when implemented properly gives the
fastest known sorting algorithm for random inputs
•
useful
for sorting arrays rather than lists
•
main
idea – pick one element, put it in its correct position, all elements < than
it to its left and others to its right
•
recursively
sort left and right halves
•
expressed
easily using recursion
Quick Sort
recursive subroutine quick_sort(a)
implicit none
integer, dimension(:), intent(inout) ::
a
integer :: i,n
n = size(a)
if ( n > 1) then
call partition(a,i)
call quick_sort(a(:i-1))
call quick_sort(a(i+1:))
end if
contains
Partition
subroutine partition(a,j)
integer, dimension(:), intent(inout) ::
a
integer,intent(out) :: j
integer :: i,temp
i = 1 ; j = size(a)
do
do
if ( i > j ) exit
if (a(i) > a(1)) exit
i = i+1
end do
Partition
do
if ((j < i) .or. (a(j) <=
a(1))) exit
j = j-1
end do
if ( i >= j) exit
temp = a(i)
a(i) = a(j)
a(j) = temp
end do
temp = a(j) ; a(j) = a(1) ; a(1) = temp
end subroutine partition
end subroutine quick_sort
Tail Recursion
• Any number of recursive calls
• Complex control flow
• Difficult to understand
• Linear Recursion
• Tail recursion
– The recursive call occurs as the last
statement
– Can be easily translated to iterative
programs
• General recursive programs can also be
translated to iterative programs
• But this requires, in general, a stack
(FIFO data structure)
• Computationally expensive
Keyword Parameters
•
The
actual parameter list should match the dummy parameter list in order
•
might
prove to be cumbersome when argument lists are large
•
keyword
argument is a solution to this problem
•
Suppose
test(first, second, third)
...
end subroutine test
•
the
following calls are legal:
test(3, 6, 7)
test(first = 3, third = 7, second =
6)
test(3, third = 7, second = 6)
•
Explicit
interface for the procedure required
•
Declare
it in a module which can be `used' by the calling routine
Optional Parameters
• Parameters can be optional
• Declare
– integer, intent(in), optional:: limit
• The actual argument for limit can be left out in a call and
default values can be used
• A logical function to test whether an optional argument is
present or not
if (PRESENT(limit) then
...
else
...
endif