Download presentation
Presentation is loading. Please wait.
Published byMagdalene Dennis Modified over 9 years ago
1
20-1 Computing Fundamentals with C++ Object-Oriented Programming and Design, 2nd Edition Rick Mercer Franklin, Beedle & Associates, 1999 ISBN 1-887902-36-8 Presentation Copyright 1999, Franklin, Beedle & Associates Students who purchase and instructors who adopt Computing Fundamentals with C++, Object-Oriented Programming and Design by Rick Mercer are welcome to use this presentation as long as this copyright notice remains intact.
2
20-2 Chapter 20 Recursion Chapter Objectives Compare iterative and recursive solutions to the same problem Identify the recursive case and the base (or simple) case in a recursive algorithm Implement recursive methods
3
20-3 20.1 Understanding Recursion Recursion is used to describe things. Here are some everyday examples Show everything in a folder and all it subfolders show everything in top folder show everything in each subfolder in the same manner How to look up a word in a dictionary look up a word (use alphabetical ordering) or look up word to define the word you are looking up A waiting line is either empty or has someone at the front of the waiting line followed by a waiting line. Can we have a waiting line with one person?
4
20-4 Recursive definition for arithmetic definition Arithmetic expression is defined as a numeric constant an numeric identifier an arithmetic expression enclosed in parentheses 2 arithmetic expressions with a binary operator like + - / or * The term arithmetic expression is defined using the term arithmetic expression but the first two possibilities don’t
5
20-5 Mathematical Examples Consider the factorial function (0!=1) The recursive definition: What is f(2)? ___________ What is f(3)? ___________
6
20-6 Recursive and non-recursive solutions // Non-recursive solution, using a loop int factRep(int n) { // precondition: n >= 0 long result = 1; long result = 1; for(int j = 2; j <= n; j++) for(int j = 2; j <= n; j++) result = j * result; result = j * result; return result; return result;} // Recursive solution int factRec(int n) { // precondition: n >= 0 if(n == 0) if(n == 0) return 1; // Simple case return 1; // Simple case else else return n * factRec(n - 1); // Recursive case return n * factRec(n - 1); // Recursive case }// Don't call factRec(n + 1)!
7
20-7 Basic Recursion Consider this weird way to raise 2 to the 5th each method is a similar but simpler version of the previous method eventually, the method returns a value without any further calls static int twoRaisedTo0() { return 1; } static int twoRaisedTo0() { return 1; } static int twoRaisedTo1() { return 2 * twoRaisedTo0(); } static int twoRaisedTo1() { return 2 * twoRaisedTo0(); } static int twoRaisedTo2() { return 2 * twoRaisedTo1(); } static int twoRaisedTo2() { return 2 * twoRaisedTo1(); } static int twoRaisedTo3() { return 2 * twoRaisedTo2(); } static int twoRaisedTo3() { return 2 * twoRaisedTo2(); } static int twoRaisedTo4() { return 2 * twoRaisedTo3(); } static int twoRaisedTo4() { return 2 * twoRaisedTo3(); } static int twoRaisedTo5() { return 2 * twoRaisedTo4(); } static int twoRaisedTo5() { return 2 * twoRaisedTo4(); } int main() int main() { System.out.println("2 to the 5th = " + twoRaisedTo5()); System.out.println("2 to the 5th = " + twoRaisedTo5()); } // Output: 2 to the 5th = 32 // Output: 2 to the 5th = 32
8
20-8 A Less Tedious and More General Option (without a loop) Consider twoRaisedTo(0), which would return 1 Make this method return 2 with twoRaisedTo(1) int twoRaisedTo(int n) int twoRaisedTo(int n) { if(n == 0) if(n == 0) return 1; return 1; else else // Express twoRaisedTo 4, 3, 2, 1, and 0: // Express twoRaisedTo 4, 3, 2, 1, and 0: return 2 * __________________________________ ; return 2 * __________________________________ ; } How many method calls occur with twoRaisedTo(5) ?
9
20-9 Recursive methods The previous method is known as a recursive method because it calls itself Each time, the method calls a simpler version The answers should be return 2 * twoRaisedTo(n-1); and 5 return 2 * twoRaisedTo(n-1); and 5 Eventually no further calls are necessary the simple case is reached and the method simply returns 1 which goes back to the previous call returns 1 which goes back to the previous call return 2 * twoRaisedTo(1); // 2 * 1 = 2 return 2 * twoRaisedTo(1); // 2 * 1 = 2
10
20-10 Mathematical Examples twoRaisedTo can be written as follows If n >= 0, use the top line as the definition of the method If n == 0, use the bottom line Notice that twoRaisedTo appears on both sides of =, which makes this a recursive definition Recursive definitions must have a simple case no method name to the right of =
11
20-11 Complete the Substitutions Can you evaluate f(5) before evaluating f(4)? Now perform back substitution fill in the blanks above from top to bottom twoRaisedTo(0) = ____ // simple case: The first answer you can write twoRaisedTo(1) = 2 * twoRaisedTo(0) = 2 * ____ twoRaisedTo(2) = 2 * twoRaisedTo(1) = 2 * ____ twoRaisedTo(3) = 2 * twoRaisedTo(2) = 2 * ____ twoRaisedTo(4) = 2 * twoRaisedTo(3) = 2 * ____ twoRaisedTo(5) = 2 * twoRaisedTo(4) = 2 * _____ or
12
20-12 20.2 Defining Base and Recursive Cases When writing recursive methods Make sure there is at least one base case at least one situation where a recursive call is not made. There could be more than 1 –The method might return a value, or do nothing at all There could be one or more recursive cases a recursive call must be a simpler version of the same problem –the recursive call should bring the method closer to the base case perhaps pass n-1 rather than n.
13
20-13 How Recursion works Method calls generate activation records Depending on the system, the activation record might store all parameter values and local values return point -- where to go after the method finishes imagine all this is in a box the data is stored in an activation frame and pushed onto a stack -- one on top of the other when the method finishes, the activation frame stack is popped it disappears, control returns to where it was called
14
20-14 A method that calls itself void forward(int n) { if(n > 1) if(n > 1) forward(n - 1); // recursive call: n goes toward 0 forward(n - 1); // recursive call: n goes toward 0 // RP# FORWARD // RP# FORWARD System.out.println(n); System.out.println(n);} int main() { int arg = 3; int arg = 3; forward(arg); forward(arg); // RP# MAIN // RP# MAIN arg = 999; arg = 999; return 0; return 0;} RP# MAIN arg 3 RP# MAIN arg 3 RP# MAIN arg 3 RP# FORWARD n 3 RP# MAIN arg 3 RP# FORWARD n 3 RP# FORWARD n 3 RP# FORWARD n 2 RP# FORWARD n 2 n 1
15
20-15 The simple case is reached Several activation frames are stacked When parameter (n) == 1, there is no recursive call. (1) execute the base case when n == 1 System.out.println(n); System.out.println(n); The output is 1 and the method is done RP# MAIN arg 3 RP# FORWARD n 3 RP# FORWARD n 2 n 1 (1)
16
20-16 Returning back to main (2) Return to previous call and pop box on top continue from RP# FORWARD, print 2 (3) Return to previous call and pop box on top continue from RP# FORWARD, print 3 (4) Return to main, pop box on top execute arg = 999 (to indicate we're back in main) The main method is done, Output is 123 The main method is done, Output is 123 RP# MAIN arg 3 RP# FORWARD n 3 RP# FORWARD n 2 RP# MAIN arg 3 RP# FORWARD n 3 RP# MAIN arg 3 999 (2) (3) (4)
17
20-17 Too much recursion can be costly Consider the Fibonacci numbers 1, 1, 2, 3, 5, 8, 13, 21, …. Demonstrate Fibonacc.cpp Demonstrate Fibonacc.cpp long fib(int n) { // counts calls to fib methodCalls++; methodCalls++; if(n == 0 || n == 1) if(n == 0 || n == 1) return 1; return 1; else else return fib(n-1)+fib(n-2); return fib(n-1)+fib(n-2);}
18
20-18 Fib(5) calls fib(4) once, fib(3) twice, fib(2) thrice, fib (1) five times and fib(0) thrice fib(7) = 21 methodCalls = 41 fib(8) = 34 methodCalls = 67 fib(9) = 55 methodCalls = 109 fib(10) = 89 methodCalls = 177 fib(11) = 144 methodCalls = 287 fib(12) = 233 methodCalls = 465 fib(13) = 377 methodCalls = 753 fib(14) = 610 methodCalls = 1219 fib(15) = 987 methodCalls = 1973 fib(16) = 1597 methodCalls = 3193 fib(17) = 2584 methodCalls = 5167 fib(18) = 4181 methodCalls = 8361 fib(19) = 6765 methodCalls = 13529 fib(20) = 10946 methodCalls = 21891
19
20-19 Recursive Fibonacci grows Exponentially
20
20-20 20.3 Converting Decimal Numbers to Other Bases Problem: Convert a decimal (base 10) number into other bases Function Call Output Function Call Output convert(99, 2) 1100011 convert(99, 2) 1100011 convert(99, 3) 10200 convert(99, 3) 10200 convert(99, 4) 1203 convert(99, 4) 1203 convert(99, 5) 344 convert(99, 5) 344 convert(99, 6) 243 convert(99, 6) 243 convert(99, 7) 201 convert(99, 7) 201 convert(99, 8) 143 convert(99, 8) 143 convert(99, 9) 120 convert(99, 9) 120
21
20-21 Digits are multiplied by powers of the base 10, 8, 2, or whatever First: converting from other bases to decimal Decimal numbers multiply digits by powers of 10 9507 10 = 9 x 10 3 + 5 x 10 2 + 0 x 10 1 + 7 x 10 0 Octal numbers powers of 8 1567 8 = 1 x 8 3 + 5 x 8 2 + 6 x 8 1 + 7 x 8 0 = 512 + 320 + 48 + 7 = 887 10 = 512 + 320 + 48 + 7 = 887 10 Binary numbers powers of 2 1011 2 = 1 x 2 3 + 1 x 2 2 + 1 x 2 1 + 1 x 2 0 = 8 + 4 + 2 + 1 = 15 10 = 8 + 4 + 2 + 1 = 15 10
22
20-22 Converting base 10 to base 2 1) divide number by new base (2), write remainder (1) 2) divide quotient (2), write new remainder (0) to left 3) divide quotient (1), write new remainder (1) to left __2_ __2_ 2) 5 Remainder = 1 2) 5 Remainder = 1 __1_ __1_ 2) 2 Remainder = 0 2) 2 Remainder = 0 __0_ __0_ 2) 1 Remainder = 1 2) 1 Remainder = 1 Stop when the quotient is 0 5 10 = 101 2 Print remainders in reverse order
23
20-23 Converting base 10 to base 8 1) divide number by new base (8), write remainder (1) 2) divide quotient (2), write new remainder (0) to left 3) divide quotient (1), write new remainder (1) to left _12_ _12_ 8)99 Remainder = 3 8)99 Remainder = 3 __1_ __1_ 8)12 Remainder = 4 8)12 Remainder = 4 __0_ __0_ 8) 1 Remainder = 1 8) 1 Remainder = 1 Stop when the quotient is 0 99 10 = 134 8 Print remainders in reverse order
24
20-24 Solutions We could either store remainders in an array and reverse it or write out the remainders in reverse order have to postpone the output until we get quotient = 0 Algorithm while the decimal number > 0 while the decimal number > 0 { Divide the decimal number by the new base Divide the decimal number by the new base Set the decimal number to the decimal number divided by the base Set the decimal number to the decimal number divided by the base Write the remainder to the left of any preceding remainders Write the remainder to the left of any preceding remainders }
25
20-25 Base Case Recursive Case Base case if decimal number being converted = 0 do nothing Recursive case if decimal number being converted > 0 convert a simpler version of the problem –use the quotient as the argument to the next call print the remainder
26
20-26 Convert a number to other bases void convert(int decimalNumber, int base) { if(decimalNumber > 0) if(decimalNumber > 0) { // This recursive call makes progress { // This recursive call makes progress // towards the simple case by passing // towards the simple case by passing // the quotient in each recursive call // the quotient in each recursive call convert(decimalNumber / base, base); convert(decimalNumber / base, base); // RP# CONVERT System.out.print(decimalNumber % base); System.out.print(decimalNumber % base); // After the last call, write the // After the last call, write the // remainders in reverse order // remainders in reverse order }} Demonstrate Fibonacci.cpp
27
20-27 99 base 8 // Base case where // nothing happens, so return // print 1 number % 8 = 1 % 8 = 1 // print 4 number % 8 = 12 % 8 = 4 // print 3 number % 8 = 99 % 8 = 3 // Output from inside the if 143 IN MAIN number 99 base 8 RP# CONVERT number 99 base 8 RP# CONVERT number 12 base 8 RP# CONVERT number 1 base 8 number 0 base 8
Similar presentations
© 2024 SlidePlayer.com Inc.
All rights reserved.