200 likes | 347 Views
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
E N D
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 factImplicit noneinteger:: N, z read *, N call fct(N, z) print *, zcontainsrecursive subroutine fct(M, y)implicit noneinteger,intent(in):: Minteger, intent(out):: y if (M >= 1) then call fct(M - 1, y) y = M * y else y = 1 endifend subroutine end program
Recursive Function Program factimplicit none integer:: N, z read *, N z = fct(N) print *, zcontainsrecursive integer function fct(M) result(answer)implicit none integer:: M, answer if (M /= 0) then answer = M * fct(M - 1) else answer = 1 endifend function end program
Fibonacci Numbers Program fibonacciimplicit noneinteger:: N, z read *, Ncall fib(N, z) print *, zcontainsrecursive subroutine fib(M, y)implicit noneinteger, intent(in):: Minteger, intent(out):: yinteger:: y1, y2 if (M > 1) thencall fib(M - 1, y1)call fib(M - 1, y2) y = y1 + y2 else y = 1 endifend subroutine end program
Tower of Hanoi Problem • Initial Configuration 1 2 3 4 5 6 Original pole Spare pole Final pole
Final Configuration 1 2 3 4 5 6 Original pole Spare pole Final pole
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: 1 2 3 4 6 5 Original pole sparepole Finalpole
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 recursivesubroutine quick_sort(a) implicitnone integer, dimension(:), intent(inout) :: a integer :: i,n n = size(a) if ( n > 1) then call partition(a,i) callquick_sort(a(:i-1)) call quick_sort(a(i+1:)) endif 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 enddo
Partition do if ((j < i) .or. (a(j) <= a(1))) exit j = j-1 enddo if ( i >= j) exit temp = a(i) a(i) = a(j) a(j) = temp enddo temp = a(j) ; a(j) = a(1) ; a(1) = temp endsubroutine partition endsubroutine 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