250 likes | 406 Views
Recursion : Chapter 8 Saurav Karmakar. Recursive Function Call. a recursion function is a function that either directly or indirectly makes a call to itself. but we need to avoid making an infinite sequence of function calls (infinite recursion). Finding a Recursive Solution.
E N D
Recursive Function Call • a recursion function is a function that either directly or indirectly makes a call to itself. • but we need to avoid making an infinite sequence of function calls (infinite recursion)
Finding a Recursive Solution • A recursive solution to a problem must be written carefully • The idea is for each successive recursive call to bring you one step closer to a situation in which the problem can easily be solved • The easily solved situation is called the base case • Each recursive algorithm must have at least one base case, as well as a general (recursive) case
Mathemetical Induction To prove • Let p(n) denote the statement involving the integer variable n. The Principle of Mathematical Induction states: • If p(1) is true and, for some integer K >=1 , p(k+1) is true whenever p(k) is true then p(n) is true for all n>=1 . • 4 steps in using Induction: • Base cases; --- p(1), p(2), … • Induction hypothesis (IH); --- assume p(k) is true • Statement to be proved in induction; --- it is true for p(k+1) • Induction step. --- prove p(k+1) is true based on IH
A recursive defination int s (int n) { if (n ==1) return 1; else return s(n-1) + n; } • A few of problems: • n 0 at the beginning; • return value might be too large to fit in an int.
Printing number in Any Base const string DIGIT_TABLE = "0123456789abcdef"; const int MAX_BASE = DIGIT_TABLE.length( ); void printIntRec( int n, int base ) { if( n >= base ) printIntRec( n / base, base ); cout << DIGIT_TABLE[ n % base ]; } • Potential problems in this code: • if base>16: --- out of bound; • if base = 0: --- division by 0; • if base = 1: --- infinite loop.
General format forMany Recursive Functions if (some easily-solved condition) // base case solution statement else// general case recursive function call
When a function is called... • A transfer of control occurs from the calling block to the code of the function--it is necessary that there be a return to the correct place in the calling block after the function code is executed; this correct place is called the return address • When any function is called, the run-time stack is used--on this stack is placed an activation record for the function call
Stack Activation Frames • The activation record contains the return address for this function call, and also the parameters, and local variables, and space for the function’s return value, if non-void etc. • The activation record for a particular function call is popped off the run-time stack when the final closing brace in the function code is reached, or when a return statement is reached in the function code. • At that time the function’s return value, if non-void, is brought back to the calling block return address for use there
A recursive function int Func ( /* in */ int a, /* in */ int b ) { int result; if ( b == 0 ) // base case result = 0; else if ( b > 0 ) // first general case result = a + Func ( a , b - 1 ) ) ; // instruction 50 return result; }
Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 FCTVAL ? result ? b 2 a 5 Return Address 100 original call at instruction 100 pushes on this record for Func(5,2)
record for Func(5,2) Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 FCTVAL ? result ? b 1 a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 a 5 Return Address 100 call in Func(5,2) code at instruction 50 pushes on this record for Func(5,1)
record for Func(5,1) record for Func(5,2) Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 call in Func(5,1) code at instruction 50 pushes on this record for Func(5,0) FCTVAL ? result ? b 0 a 5 Return Address 50 FCTVAL ? result 5+Func(5,0) = ? b 1 a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 a 5 Return Address 100
Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 FCTVAL 0 result 0 b 0 a 5 Return Address 50 FCTVAL ? result 5+Func(5,0) = ? b 1 a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 a 5 Return Address 100 record for Func(5,0) is popped first with its FCTVAL record for Func(5,1) record for Func(5,2)
Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 FCTVAL 5 result 5+Func(5,0) = 5+ 0 b 1 a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 a 5 Return Address 100 record for Func(5,1) is popped next with its FCTVAL record for Func(5,2)
Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 FCTVAL 10 result 5+Func(5,1) = 5+5 b 2 a 5 Return Address 100 record for Func(5,2) is popped last with its FCTVAL
Too much recursion Can Be Dangerous Fibonacci numbers. Long fib (int n) { If (n <=1) return n; Else return fib(n-1) + fib(n-2); }
Too much Recursion Can be Dangerous • This definition will lead to exponential running time. • Reason: -- too much redundant work. • Not necessary to use recursion.
Tree • Tree is a fundamental structure in computer science. • Recursive definition: A tree is a root and zero or more nonempty subtrees. • Nonrecursive definition: A tree consists of s set of nodes and a set of directed edges that connect pairs of nodes. That is, a connected graph without loop.
Some more examples: • Factorials • Binary Search template <class Comparable> int binarySearch( const vector<Comparable> & a, const Comparable & x, int low, int high ) { if( low > high ) return NOT_FOUND; int mid = ( low + high ) / 2; if( a[ mid ] < x ) return binarySearch( a, x, mid + 1, high ); else if( x < a[ mid ] ) return binarySearch( a, x, low, mid - 1 ); else return mid; }
Divide and Conquer • Given an instance of the problem to be solved, split that into several, smaller, sub-instances (of the same problem). • Independently solve each of the sub-instances and then combine the sub-instance solutions so as to yield a solution for the original instance.
Finding ‘Greatest Common Divisor’ • gcd(A,B) = gcd(A-B, B) • template <class HugeInt> HugeInt gcd (const HugeInt &a, Const HugeInt &b ) { if( b==0 ) return a; else return gcd(b, a%b); }
Recursion or Iteration? CLARITY EFFICIENCY