Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Introduction to Recursion Please fasten your seat belts.

Similar presentations


Presentation on theme: "1 Introduction to Recursion Please fasten your seat belts."— Presentation transcript:

1 1 Introduction to Recursion Please fasten your seat belts.

2 2 Recursion is difficult to master Recursion yield elegant, concise code Yet, it is difficult to debug. Minor mistakes can be disastrous for the program Infinite recursion is the most common problem Infinite recursion is more complicated than infinite loop because it consume all the memory when stacking the current status of the function. For the inexperienced programmer, the program may sometimes report a error which has no immediate relation to the recursive function

3 3 Recursion When “something” is defined in terms of itself! Recursive methods: A method that calls itself Recursive classes: A class that contains an instance of itself

4 4 Recursion Is the "art" of defining a concept using the concept itself They are the computer science equivalent of mathematical induction In computer science terms we talk about recursive functions: functions that invoke itself Not allowed in some languages When allowed they are very powerful  They express repetition without loops  They simplify code which would otherwise be confusing and unclear. It is an important tool supporting data abstraction

5 5 Recursive Definitions Any recursive definition has to have two parts : Basis of recursion: This is a non-recursive statement establishing definition for a fixed number of objects. The bases is the condition that makes the recursion stop Recursion: It is a condition that is written in such a way that after repeated executions of this code it will reduce to the basis. // Definition of function (x raised to y) // Where y is positive BASE : x raised to 0 is 1 RECURSION: x raised to y is equal x times x raised to y-1 // Definition of function (x raised to y) // Where y is positive BASE : x raised to 0 is 1 RECURSION: x raised to y is equal x times x raised to y-1

6 6 Recurrence Relations It is an relation describing the recursive function in terms of its values on smaller inputs It will be widely used when we get to analysis of algorithms There are three methods to solve recurrences Substitution method: based on mathematical induction Iteration method: converts the recurrence into a summation. Master method: Provides bounds for recurrences of the form: T(n) = aT(n/b) + f(n)  where a >= 1, b > 1 and f(n) is a given function  Requires memorization of a few cases Recurrence will be used quite frequently when describing sorting and tree algorithms Since a few of these algorithms are recursive

7 7 BNF (Backus-Naur Form) Most Programming languages use the BNF notation to describe its syntax It is less ambiguous than English It is a generator technique. It defined how to construct, or generate, all possible syntactically valid strings of a language. It is a recursive technique ::= | ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 ::= | ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0

8 8 Understanding Recursion To understand recursion we need to understand stacks Each time a function A calls a function B the status of A is stored in the run-time stack. When the function B returns the status of A is popped from the top of the stack. Let's consider this program void whatIsThis() { char inChar; cin.get(inChar); if (inChar == '\n') cout << '\n'; else { whatIsThis(); cout << inChar; } void whatIsThis() { char inChar; cin.get(inChar); if (inChar == '\n') cout << '\n'; else { whatIsThis(); cout << inChar; }

9 9 "Exploding" the recursion Instead of imagining as stacks we could also see this as creation of new scopes at each iteration of the recursion void whatIsThis() { char inChar; cin.get(inChar); if (inChar == '\n') cout << '\n'; else { char inChar; { cin.get(inChar); if (inChar == '\n') cout << '\n'; else { cout << inChar; } cout << inChar; } void whatIsThis() { char inChar; cin.get(inChar); if (inChar == '\n') cout << '\n'; else { char inChar; { cin.get(inChar); if (inChar == '\n') cout << '\n'; else { cout << inChar; } cout << inChar; }

10 10 Stacks Is a “pile” or “collection” or “set” of items. Items can only be added to the top Items can only be taken off the top “Last-in-first-out” (”LIFO”) Thing 1 Thing 2 Thing 3 PushPop

11 11 What is a Stack? A data structure for storing items which are to be accessed in last-in first-out order (LIFO). A data structure for storing items which are to be accessed in last-in first-out order (LIFO).

12 12 Thing 1 PUSH A data structure for storing items which are to be accessed in last-in first-out order (LIFO). A data structure for storing items which are to be accessed in last-in first-out order (LIFO). What is a Stack?

13 13 Thing 1 Thing 2 PUSH What is a Stack? A data structure for storing items which are to be accessed in last-in first-out order (LIFO). A data structure for storing items which are to be accessed in last-in first-out order (LIFO).

14 14 Thing 1 pop What is a Stack? A data structure for storing items which are to be accessed in last-in first-out order (LIFO). A data structure for storing items which are to be accessed in last-in first-out order (LIFO).

15 15 Thing 1 Thing 2 PUSH What is a Stack? A data structure for storing items which are to be accessed in last-in first-out order (LIFO). A data structure for storing items which are to be accessed in last-in first-out order (LIFO).

16 16 Thing 1 Thing 2 Thing 3 PUSH What is a Stack? A data structure for storing items which are to be accessed in last-in first-out order (LIFO). A data structure for storing items which are to be accessed in last-in first-out order (LIFO).

17 17 Thing 1Thing 2 pop What is a Stack? A data structure for storing items which are to be accessed in last-in first-out order (LIFO). A data structure for storing items which are to be accessed in last-in first-out order (LIFO).

18 18 Thing 1 pop What is a Stack? A data structure for storing items which are to be accessed in last-in first-out order (LIFO). A data structure for storing items which are to be accessed in last-in first-out order (LIFO).

19 19 pop What is a Stack? A data structure for storing items which are to be accessed in last-in first-out order (LIFO). A data structure for storing items which are to be accessed in last-in first-out order (LIFO).

20 20 The Activation Stack The white box represents the computers memory. The algorithm gets the first frame at the bottom of the stack. Variables which are used within a module reside in that module’s stack frame. Algo var1 var2var3

21 21 Algo var1var2var3 Proc_1 this_varthat_var Adding Modules to the Stack When main calls a module, the module gets its own frame “pushed” on the stack. The module’s variables live in that new frame. ONLY ONLY the top frame is active. All frames underneath it are stopped.

22 22 Proc_1 this_varthat_var Algo var1var2var3 Removing modules from the stack When the module completes its instructions, it’s frame is “popped” off the stack and all of its data dies. To survive, they must actually be stored in a frame that still exists (passed back).

23 23 How In Parameters Work In formal parameters get a copy of the matching actual parameter. In the algorithm: Proc_One (this_var) In the module: procedure Proc_One(this_one in num)

24 24 Proc_One this_one 4 Algo 4 How In Parameters Work In formal parameters get a copy of the matching actual parameter. this_var that_var other_var 7 9 4

25 25 How In/Out Parameters Work In/out formal parameters act as a reference to the matching actual parameter. Reading and writing are allowed. In the algorithm: Proc_One (this_var) In the module: procedure Proc_One(this_one in/out num)

26 26 Algo 7 Proc_One this_one How In/Out Parameters Work In/out formal parameters act as a reference to the matching actual parameter. Reading and writing are allowed. R this_one <- 7 this_one <- 1 7 1 this_var that_var other_var 9 4 7 1 Print(this_one) 1

27 27 How Out Parameters Work Out formal parameters act as a reference to the matching actual parameter. Writing is only allowed at first. After writing, reading is also allowed. In the algorithm: Proc_One (this_var) In the module: procedure Proc_One(this_one out num)

28 28 How Out Parameters Work Out formal parameters act as a reference to the matching actual parameter. Writing is only allowed at first. After writing, reading is also allowed. Proc_One this_one R this_one <- 8 8 Algo this_var that_var other_var 4 7 9 8

29 29 Stack Trace Example procedure juggle (x isoftype in num, y isoftype out num, z isoftype in/out num) y <- x + z print (x, y, z) x <- z + 4 z <- x + 2 endprocedure algorithm TraceExample a, b, c isoftype num a <- 1 b <- 2 c <- 3 print(a, b, c) juggle(c, a, b) print(a, b, c) endalgorithm

30 30 Procedure Juggle(x iot in Num, y iot out Num, z iot in/out Num) y <- x + z print(x,y,z) x <- z + 4 z <- x - 2 endprocedure Output Demo abc 1 2 3 1 2 3 Juggle xyz 3 3 5 2 5 4 3 Algorithm Demo a, b, c isoftype num a <- 1 b <- 2 c <- 3 print(a,b,c) juggle(c,a,b) print(a,b,c) endalgorithm R R 6 5 4

31 31 Recursive Functions Like mathematical definitions, functions can be recursive Direct recursion: Occurs when a function is called in its own body Indirect recursion: Occurs when one function initiates a sequence of function invocations that eventually invokes the original func A(int x) {. A(20);. } func A(int x) {. A(20);. } Direct Recursion func A(int x) {. B(20);. } func A(int x) {. B(20);. } func B(int x) {. A(20);. } func B(int x) {. A(20);. } Indirect Recursion

32 32 A Recursive Procedure Problem: Count from N to 10. procedure CountToTen (/* in */ int n) { if (count <= 10) then { print (count)// work CountToTen (count + 1)// recurse }//endif }//endprocedure CountToTen Call the procedure CountToTen (7)

33 33 Tracing The Recursion To keep track of recursive execution, do what a computer does: maintain information on an activation stack. Each stack frame contains : Module identifier and variables Any unfinished business ModuleID: Data values Unfinished business

34 34 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7

35 35 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7

36 36 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7

37 37 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen

38 38 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7878 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen

39 39 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7878 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen

40 40 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7878 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9

41 41 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 789789 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9

42 42 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 789789 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9

43 43 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 789789 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=10

44 44 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7 8 9 10 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=10

45 45 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7 8 9 10 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=10

46 46 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7 8 9 10 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=10 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=11

47 47 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7 8 9 10 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=10

48 48 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7 8 9 10 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9

49 49 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7 8 9 10 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen

50 50 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 7 8 9 10

51 51 7 8 9 10 Return to the algorithm.

52 52 Reversing the Work and Recursion Problem: Count from 10 to N. procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen Now the work will happen as the frames pop off the stack!

53 53 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=7

54 54 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=7

55 55 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen

56 56 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen

57 57 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=9

58 58 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=9

59 59 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=10

60 60 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=10

61 61 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=10 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=11

62 62 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 10 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=10

63 63 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 10 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=9 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=10

64 64 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 10 9 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=9

65 65 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 10 9 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=9

66 66 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 10 9 8 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen

67 67 procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endif endprocedure //CountToTen CountToTen: count=7 10 9 8 CountToTen: count=8 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen

68 68 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=7 10 9 8 7

69 69 procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endif endprocedure //CountToTen CountToTen: count=7 10 9 8 7

70 70 10 9 8 7 Return to the algorithm.

71 71 What is Recursion? Recursion is when a function either directly or indirectly makes a call to itself. Recursion is a powerful problem solving tool. Many mathematical functions and algorithms are most easily expressed using recursion.

72 72 How does it work? Functions are implemented using an internal stack of activation records. The activation record for the currently active function is at the top of the stack. Each time a function is called a new activation record is pushed on the stack. When a function returns, the stack is popped and the activation record of the calling method is on top of the stack.

73 73 How does it work? The function being called, and whose activation record is being pushed on the stack, can be different from the calling function (e.g., when main calls a function). Or, the function being called can be a different instance of the calling subprogram. Each instance of the function has its own parameters and local variables.

74 74 Solving Recursive Problems See recursive solutions as two sections: Current Rest N! = N * (N-1)! 7! = 7 * 6! 7! = 7 * (6 * 5 * 4 * 3 * 2 * 1 * 1)

75 75 Example Many mathematical functions are defined recursively. For example, the factorial function: N!= N * (N-1)! for N>0 0! = 1 l We have defined factorial in terms of a smaller (or simpler) instance of itself. l We must also define a base case or stopping condition.

76 76 Recursive Function Call A recursive call is a function call in which the called function is the same as the one making the call. In other words, recursion occurs when a function calls itself! We must avoid making an infinite sequence of function calls (infinite recursion).

77 77 Finding a Recursive Solution Each successive recursive call should bring you closer to a situation in which the answer is known. A case for which the answer is known (and can be expressed without recursion) is called a base case. Each recursive algorithm must have at least one base case, as well as the general (recursive) case

78 78 General format for many recursive functions if (some condition for which answer is known) // base case solution statement else // general case recursive function call SOME EXAMPLES...

79 79 Writing a recursive function to find n factorial DISCUSSION The function call Factorial(4) should have value 24, because that is 4 * 3 * 2 * 1. For a situation in which the answer is known, the value of 0! is 1. So our base case could be along the lines of if ( number == 0 ) return 1;

80 80 Writing a recursive function to find Factorial(n) Now for the general case... The value of Factorial(n) can be written as n * the product of the numbers from (n - 1) to 1, that is, n * (n - 1) *... * 1 or, n * Factorial(n - 1) And notice that the recursive call Factorial(n - 1) gets us “closer” to the base case of Factorial(0).

81 81 Recursive Function Example: Factorial Problem: calculate n! (n factorial) n! = 1 if n = 0 n! = 1 * 2 * 3 *...* n if n > 0 Recursively: if n = 0, then n! = 1 if n > 0, then n! = n * (n-1)!

82 82 Factorial Function Int RecFactorial( /* in */ int n) // Calculates n factorial, n! // Precondition: n is a non-negative // integer { if (n <= 0) then return 1 else return n * RecFactorial(n-1) }

83 83 1 Int RecFactorial(/*in*/int n) 3 { 4 if (n <= 0) then 5 return 1; 6 else 7 return n * RecFactorial(n-1); 8 } main(...) {... 20 cout<<(fact(3));... 20 return address n value 33 * fact(2)7 return address n value 22 * fact(1)7 return address n value 11 * fact(0)7 return address n value 01

84 84 20 return address n value 33 * fact(2) 7 return address n value 22 * fact(1) 7 return address n value 11 * fact(0) 7 return address n value 01 1 * 12 * 13 * 2 returns 6 to main() 1 Int RecFactorial(/*in*/int n) 3 { 4 if (n <= 0) then 5 return 1; 6 else 7 return n * RecFactorial(n-1); 8 } main(...) {... 20 cout<<(fact(3));...

85 85 if (0 = 0) then Fact returns 1 else Fact returns 1 endif endfunction //Fact if (0 = 0) then Fact returns 1 else Fact returns 1 endif endfunction //Fact if (1 = 0) then Fact returns 1 else Fact returns 1 * Fact(0) endif endfunction //Fact if (1 = 0) then Fact returns 1 else Fact returns 1 * Fact(0) endif endfunction //Fact if (2 = 0) then Fact returns 1 else Fact returns 2 * Fact(1) endif endfunction //Fact if (2 = 0) then Fact returns 1 else Fact returns 2 * Fact(1) endif endfunction //Fact if (3 = 0) then Fact returns 1 else Fact returns 3 * Fact(2) endif endfunction //Fact if (3 = 0) then Fact returns 1 else Fact returns 3 * Fact(2) endif endfunction //Fact algorithm Test ans <- Fact(3) endalgorithm algorithm Test ans <- Fact(3) endalgorithm

86 86 Tracing Details function RecFactorial (2) if (2 <= 0) then RecFactorial returns 1 else return 2 * RecFactorial(1) function RecFactorial (2) if (2 <= 0) then RecFactorial returns 1 else return 2 * RecFactorial(1) 1. Actual parameters stored on the stack 2. Recursive call to RecFactorial 4. Unfinished Business 3. Create a new Stack Frame 5. Return value and release stack frame

87 87 Activation Stack for Factorial Call the function: answer <- Fact(5) Main Algorithm: Unfinished: answer <- Fact (5)

88 88 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4)

89 89 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4) Fact. 2nd: N=4, Unfinished: 4*Fact(3)

90 90 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4) Fact. 2nd: N=4, Unfinished: 4*Fact(3) Fact. 3rd: N=3, Unfinished: 3*Fact(2)

91 91 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4) Fact. 2nd: N=4, Unfinished: 4*Fact(3) Fact. 3rd: N=3, Unfinished: 3*Fact(2) Fact. 4th: N=2, Unfinished: 2*Fact(1)

92 92 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4) Fact. 2nd: N=4, Unfinished: 4*Fact(3) Fact. 3rd: N=3, Unfinished: 3*Fact(2) Fact. 4th: N=2, Unfinished: 2*Fact(1) Fact. 5th: N=1, Unfinished: 1*Fact(0)

93 93 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4) Fact. 2nd: N=4, Unfinished: 4*Fact(3) Fact. 3rd: N=3, Unfinished: 3*Fact(2) Fact. 4th: N=2, Unfinished: 2*Fact(1) Fact. 5th: N=1, Unfinished: 1*Fact(0) Fact. 6th: N=0, Finished: returns 1

94 94 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4) Fact. 2nd: N=4, Unfinished: 4*Fact(3) Fact. 3rd: N=3, Unfinished: 3*Fact(2) Fact. 4th: N=2, Unfinished: 2*Fact(1) Fact. 5th: N=1, Finished: returns 1*1

95 95 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4) Fact. 2nd: N=4, Unfinished: 4*Fact(3) Fact. 3rd: N=3, Unfinished: 3*Fact(2) Fact. 4th: N=2, Finished: returns 2*1

96 96 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4) Fact. 2nd: N=4, Unfinished: 4*Fact(3) Fact. 3rd: N=3, Finished: returns 3*2

97 97 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Unfinished: 5*Fact(4) Fact. 2nd: N=4, Finished: returns 4*6

98 98 Activation Stack for Factorial Main Algorithm: Unfinished: answer <- Fact (5) Fact. 1st: N=5, Finished: returns 5*24

99 99 Activation Stack for Factorial Main Algorithm: Finished: answer <- 120

100 100 Exponentiation base exponent e.g. 5 3 Could be written as a function Power(base, exp)

101 101 Can we write it recursively? b e = b * b (e-1) What’s the limiting case? When e = 0 we have b 0 which always equals? 1 LB

102 102 Another Recursive Function function Power returnsa Num(base, exp isoftype inNum) // Computes the value of Base Exp // Pre: exp is a non-negative integer if (exp = 0) then Power returns 1 else Power returns base * Power(base, exp-1) endif endfunction //Power Power x N = x * x N-1 for N>0 x 0 = 1

103 103 Function Power returnsa Num (base, exp isoftype in Num) //Computes the value of Base Exp //Preconditions: exp is a non-negative integer if(exp = 0 ) then Power returns 1 else Power returns (base * Power(base, exp – 1)) endif endfunction //Power Activations Stack Example Algo: total <- Power(3,4) Power base = 3 exp = 4 3 *Power(3,3)Power base = 3 exp = 3 3 *Power(3,2)Power base = 3 exp = 2 3 *Power(3,1)Power base = 3 exp = 1 3 *Power(3,0) 1 Power base = 3 exp = 0 Finished: 1 Total <- 81 1 3 9 27 1 3 9 27 81

104 104 In the year 1202 a distinguished Italian mathematician, Leonardo of Pisa, also known as Fibonacci, published the following puzzle: The Man… The Man… (1170-1250)

105 105 The Puzzle A man has an infant male-female pair of rabbits in a hutch entirely surrounded by a wall. We wish to know how many rabbits can be bred from this pair in one year, if the nature of the rabbits is such that every month they breed one other male-female pair which begins to breed in the second month after their birth. Assume that no rabbits die during the year.

106 106 A Tree Diagram for Fibonacci’s Puzzle

107 107 Observations The number of rabbits at the beginning of any month equals the number of rabbits of the previous month plus the number of new pairs. The number of new pairs at the beginning of a month equals the number of pairs two months ago. One gets the sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …233

108 108 snails nautilus other sea shells 11 2 3 5 8 13 The Occurrence in Nature…

109 109 Fibonacci Numbers & Branching Plants

110 110 Fibonacci Fingers? 2 hands each of which has... 5 fingers, each of which has... 3 parts separated by... 2 knuckles

111 111 Fibonacci Numbers & Pine Cones 13 counterclockwise 8 clockwise

112 112 Fibonacci Numbers & Sunflowers 34 counterclockwise 55 clockwise

113 113 Fibonacci sequence Recursive definition f(0) = 1 f(1) = 1 f(n) = f(n-1) + f(n-2)

114 114 Fibonacci Number Sequence if n = 1, then Fib(n) = 1 if n = 2, then Fib(n) = 1 if n > 2, then Fib(n) = Fib(n-2) + Fib(n-1) Numbers in the series: 1, 1, 2, 3, 5, 8, 13, 21, 34,... A More Complex Recursive Function

115 115 Fibonacci Sequence Function function Fib returnsaNum (n iot inNum) // Calculates the nth Fibonacci number // Precondition: N is a positive integer if ((n = 1) OR (n = 2)) then Fib returns 1 else Fib returns Fib(n-2) + Fib(n-1) endif endfunction //Fibonacci

116 116 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5)

117 117 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns Fib(3) + Fib(4)

118 118 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns Fib(3) + Fib(4) Fib(3): Fib returns Fib(1) + Fib(2)

119 119 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns Fib(3) + Fib(4) Fib(3): Fib returns Fib(1) + Fib(2) Fib(1): Fib returns 1

120 120 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns Fib(3) + Fib(4) Fib(3): Fib returns 1 + Fib(2)

121 121 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns Fib(3) + Fib(4) Fib(3): Fib returns 1 + Fib(2) Fib(2): Fib returns 1

122 122 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns Fib(3) + Fib(4) Fib(3): Fib returns 1 + 1

123 123 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4)

124 124 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4) Fib(4): Fib returns Fib(2) + Fib(3)

125 125 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4) Fib(4): Fib returns Fib(2) + Fib(3) Fib(2): Fib returns 1

126 126 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4) Fib(4): Fib returns 1 + Fib(3)

127 127 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4) Fib(4): Fib returns 1 + Fib(3) Fib(3): Fib returns Fib(1) + Fib(2)

128 128 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4) Fib(4): Fib returns 1 + Fib(3) Fib(3): Fib returns Fib(1) + Fib(2) Fib(1): Fib returns 1

129 129 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4) Fib(4): Fib returns 1 + Fib(3) Fib(3): Fib returns 1 + Fib(2)

130 130 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4) Fib(4): Fib returns 1 + Fib(3) Fib(3): Fib returns 1 + Fib(2) Fib(2): Fib returns 1

131 131 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4) Fib(4): Fib returns 1 + Fib(3) Fib(3): Fib returns 1 + 1

132 132 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + Fib(4) Fib(4): Fib returns 1 + 2

133 133 Tracing with Multiple Recursive Calls Main Algorithm: answer <- Fib(5) Fib(5): Fib returns 2 + 3

134 134 Tracing with Multiple Recursive Calls Main Algorithm: answer <- 5

135 135 Fib(5) Fib(3) Fib(4) Fib(3)Fib(2) Fib(1) Fib(0)Fib(1)Fib(0)Fib(2)Fib(1) Fib(0) 15 calls to Fib to find the 5th Fibonacci number!!!

136 136 Rules of Recursion First two fundamental rules of recursion: Base cases: Always have at least one case that can be solved without using recursion. Make progress: Any recursive call must make progress towards the base case.

137 137 Rules of Recursion Third fundamental rule of recursion: “You gotta believe”: Always assume that the recursive call works.

138 138 Rules of Recursion Fourth fundamental rule of recursion: Compound interest rule: Never duplicate work by solving the same instance of a problem in separate recursive calls.

139 139 Towers of Hanoi Many, many years ago, in a distant part of the Orient -- in the Vietnamese city of Hanoi -- the Emperor devised a puzzle, declaring that its solver could have the job of wise person. The puzzle consisted of N disks and three poles: A (the source), B (the destination), and C (the spare)

140 140 Towers of Hanoi BCA

141 141 Towers of Hanoi BCA

142 142 Towers of Hanoi BCA

143 143 Towers of Hanoi BCA

144 144 Towers of Hanoi BCA

145 145 Towers of Hanoi BCA

146 146 Towers of Hanoi BCA

147 147 Towers of Hanoi BCA

148 148 Towers of Hanoi A pseudocode description of the solution is: Towers(Count, Source, Dest, Spare) if (Count is 1) Move the disk directly from Source to Dest else { Solve Towers(Count-1, Source, Spare, Dest) Solve Towers(1, Source, Dest, Spare) Solve Towers(Count-1, Spare, Dest, Source) }

149 149 Towers of Hanoi void solveTowers( int count, char source, char dest, char spare){ if (count == 1) cout<<“Move disk from pole “ << source << " to pole " << destination <<endl; else { towers(count-1, source, spare, destination); towers(1, source, destination, spare); towers(count-1, spare, destination, source); }//end if }//end solveTowers

150 150 Pascal Triangle (Is this recursive?)

151 151 Pascal Triangle

152 152 Pascal Triangle The combinations of n items taken r at a time. For example: three items: a b c taken 2 at a time: ab ac bc Thus there are three combinations of 3 items taken 2 at a time. In General: C(n,r) = n!/(r!(n-r))! Obviously you can calculate C(n,r) using factorials.

153 153 Pascal Triangle Most of you know this leads to Pascals Triangle: n 0 1 1 1 1 2 1 2 1 3 1 3 3 1 4 1 4 6 4 1 5 1 5 10 10 5 1 This can also be written: r 0 1 2 3 4 5 n 0 1 1 1 1 2 1 2 1 3 1 3 3 1 4 1 4 6 4 1 5 1 5 10 10 5 1

154 154 Pascal Triangle C(n,r) occurs in many places in mathematics, statistics, chemistry, physics and business. Note from Pascal's Triangle that: C(n,r) = C(n-1, r-1) + C(n-1,r) This leads to the recurrence for nonnegative r and n, C(n,r) = | 1 if r = 0 or r = n, | 0 if r > n, | C(n-1, r-1) + C(n-1,r) otherwise.

155 155 Pascal Triangle This immediately leads to the recursive function for combinations: int C(int n, int r) { if((r == 0) || (r == n)) return 1; else if(r > n) return 0; else return C(n-1, r-1) + C(n-1, r); }

156 156 Recall that... Recursion occurs when a function calls itself (directly or indirectly). Recursion can be used in place of iteration (looping). Some functions can be written more easily using recursion.

157 157 What is the value of rose(25) ? int rose (int n) { if ( n == 1 ) // base case return 0; else // general case return ( 1 + rose ( n / 2 ) ); }

158 158 Finding the value of rose(25) rose(25) the original call = 1 + rose(12) first recursive call = 1 + ( 1 + rose(6) ) second recursive call = 1 + ( 1 + ( 1 + rose(3) ) ) third recursive call = 1 + ( 1 + ( 1 + (1 + rose(1) ) ) ) fourth recursive call = 1 + 1 + 1 + 1 + 0 = 4

159 159 Writing recursive functions There must be at least one base case, and at least one general (recursive) case. The general case should bring you “closer” to the base case. The parameter(s) in the recursive call cannot all be the same as the formal parameters in the heading. Otherwise, infinite recursion would occur. In function rose( ), the base case occurred when (n == 1) was true. The general case brought us a step closer to the base case, because in the general case the call was to rose(n/2), and the argument n/2 was closer to 1 (than n was).

160 160 Recursion for Repetition while ( ) while ( ) void recWhile() { if ( ) recWhile(); } void recWhile() { if ( ) recWhile(); } void anotherRecWhile() { if ( ) AnotherRecWhile(); ; } void anotherRecWhile() { if ( ) AnotherRecWhile(); ; } An arbitrary while loop An equivalent recursive function …Infinite recursion

161 161 Three-Question Method of verifying recursive functions Base-Case Question: Is there a nonrecursive way out of the function? Smaller-Caller Question: Does each recursive function call involve a smaller case of the original problem leading to the base case? General-Case Question: Assuming each recursive call works correctly, does the whole function work correctly?

162 162 Guidelines for writing recursive functions 1. Get an exact definition of the problem to be solved. 2. Determine the size of the problem to be solved on this call to the function. On the initial call, the size of the whole problem is expressed by the actual parameter(s). 3. Identify and solve the base case(s) which have non- recursive solutions. 4. Identify and solve the general case(s) in terms of smaller (recursive) cases of the same problem.

163 163 struct ListType { int length ; // number of elements in the list int info[ MAX_ITEMS ] ; } ; ListType list ; struct ListType

164 164 Recursive function to determine if value is in list PROTOTYPE bool ValueInList( ListType list, int value, int startIndex ) ; Already searched Needs to be searched 74 36... 95 list[0] [1] [startIndex] 75 29 47... [length -1] index of current element to examine

165 bool ValueInList ( ListType list, int value, int startIndex ) // Searches list for value between positions startIndex // and list.length-1 // Pre: list.info[ startIndex ].. list.info[ list.length - 1 ] // contain values to be searched // Post: Function value = // ( value exists in list.info[ startIndex ].. list.info[ list.length - 1 ] ) { if ( list.info[startIndex] == value )// one base case return true ; else if (startIndex == list.length -1 ) // another base case return false ; else // general case return ValueInList( list, value, startIndex + 1 ) ; } 165

166 166 “Why use recursion?” Many solutions could have been written without recursion, by using iteration instead. The iterative solution uses a loop, and the recursive solution uses an if statement. However, for certain problems the recursive solution is the most natural solution. This often occurs when pointer variables are used.

167 167 struct NodeType { int info ; NodeType* next ; } class SortedType { public :... // member function prototypes private : NodeType* listData ; } ; struct ListType

168 168 RevPrint(listData); A B C D E FIRST, print out this section of list, backwards THEN, print this element listData

169 169 Base Case and General Case A base case may be a solution in terms of a “smaller” list. Certainly for a list with 0 elements, there is no more processing to do. Our general case needs to bring us closer to the base case situation. That is, the number of list elements to be processed decreases by 1 with each recursive call. By printing one element in the general case, and also processing the smaller remaining list, we will eventually reach the situation where 0 list elements are left to be processed. In the general case, we will print the elements of the smaller remaining list in reverse order, and then print the current pointed to element.

170 170 Using recursion with a linked list void RevPrint ( NodeType* listPtr ) // Pre: listPtr points to an element of a list. // Post: all elements of list pointed to by listPtr have been printed // out in reverse order. { if ( listPtr != NULL )// general case { RevPrint ( listPtr-> next ) ; // process the rest cout info << endl ; // then print this element } // Base case : if the list is empty, do nothing } 170

171 171 Function BinarySearch( ) BinarySearch takes sorted array info, and two subscripts, fromLoc and toLoc, and item as arguments. It returns false if item is not found in the elements info[fromLoc…toLoc]. Otherwise, it returns true. BinarySearch can be written using iteration, or using recursion.

172 172 found = BinarySearch(info, 25, 0, 14 ); item fromLoc toLoc indexes 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 info 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 16 18 20 22 24 26 28 24 26 28 24 NOTE: denotes element examined

173 // Recursive definition bool BinarySearch ( ItemType info[ ], ItemType item, int fromLoc, int toLoc ) // Pre: info [ fromLoc.. toLoc ] sorted in ascending order // Post: Function value = ( item in info [ fromLoc.. toLoc] ) {int mid ; if ( fromLoc > toLoc ) // base case -- not found return false ; else { mid = ( fromLoc + toLoc ) / 2 ; if ( info [ mid ] == item ) // base case-- found at mid return true ; else if ( item < info [ mid ] ) // search lower half return BinarySearch ( info, item, fromLoc, mid-1 ) ; else // search upper half return BinarySearch( info, item, mid + 1, toLoc ) ; } } 173

174 174 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 (stack frame) for the function call.

175 175 Stack Activation Frames The activation record stores the return address for this function call, and also the parameters, local variables, and the function’s return value, if non-void. 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 this time the function’s return value, if non-void, is brought back to the calling block return address for use there.

176 // Another recursive function int Func ( int a, int b ) // Pre: a and b have been assigned values // Post: Function value = ?? { int result; if ( b == 0 ) // base case result = 0; else if ( b > 0 ) // first general case result = a + Func ( a, b - 1 ) ) ; // instruction 50 else // second general case result = Func ( - a, - b ) ; // instruction 70 return result; } 176

177 177 FCTVAL ? result ? b 2 a 5 Return Address 100 Run-Time Stack Activation Records x = Func(5, 2); // original call is instruction 100 original call at instruction 100 pushes on this record for Func(5,2)

178 178 FCTVAL ? result ? b 1 a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 a 5 Return Address 100 record for Func(5,2) call in Func(5,2) code at instruction 50 pushes on this record for Func(5,1) Run-Time Stack Activation Records x = Func(5, 2); // original call at instruction 100

179 179 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 record for Func(5,2)record for Func(5,1) call in Func(5,1) code at instruction 50 pushes on this record for Func(5,0) Run-Time Stack Activation Records x = Func(5, 2); // original call at instruction 100

180 180 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,2) record for Func(5,1) record for Func(5,0) is popped first with its FCTVAL Run-Time Stack Activation Records x = Func(5, 2); // original call at instruction 100

181 181 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,2)record for Func(5,1) is popped next with its FCTVAL Run-Time Stack Activation Records x = Func(5, 2); // original call at instruction 100

182 182 FCTVAL 10 result 5+Func(5,1) = 5+5 b 2 a 5 Return Address 100 Run-Time Stack Activation Records x = Func(5, 2); // original call at line 100 record for Func(5,2) is popped last with its FCTVAL

183 183 Show Activation Records for these calls x = Func( - 5, - 3 ); x = Func( 5, - 3 ); What operation does Func(a, b) simulate?

184 184 Tail Recursion The case in which a function contains only a single recursive call and it is the last statement to be executed in the function. Tail recursion can be replaced by iteration to remove recursion from the solution as in the next example.

185 // USES TAIL RECURSION bool ValueInList ( ListType list, int value, int startIndex ) // Searches list for value between positions startIndex // and list.length-1 // Pre: list.info[ startIndex ].. list.info[ list.length - 1 ] // contain values to be searched // Post: Function value = // ( value exists in list.info[ startIndex ].. list.info[ list.length - 1 ] ) { if ( list.info[startIndex] == value )// one base case return true ; else if (startIndex == list.length -1 ) // another base case return false ; else // general case return ValueInList( list, value, startIndex + 1 ) ; } 185

186 // ITERATIVE SOLUTION bool ValueInList ( ListType list, int value, int startIndex ) // Searches list for value between positions startIndex // and list.length-1 // Pre: list.info[ startIndex ].. list.info[ list.length - 1 ] // contain values to be searched // Post: Function value = // ( value exists in list.info[ startIndex ].. list.info[ list.length - 1 ] ) { bool found = false ; while ( !found && startIndex < list.length ) { if ( value == list.info[ startIndex ] ) found = true ; elsestartIndex++ ; } return found ; } 186

187 187 When to Use Recursion If the problem is recursive in nature therefore it is likely the a recursive algorithm will be preferable and will be less complex If both recursive and non-recursive algorithm have the same complexity it is likely that a non-recursive version will perform better and therefore should be preferred A third alternative in some problems is to use table- driven techniques  Sometimes we know that we will not use the only a few values of a particular function  If this is the case an implementation using a table would probably suffice and the performance will be better int factorial[8] = {1, 1, 2, 6, 24, 120, 720, 5040};

188 188 Use a recursive solution when: The depth of recursive calls is relatively “shallow” compared to the size of the problem. The recursive version does about the same amount of work as the nonrecursive version. The recursive version is shorter and simpler than the nonrecursive solution. SHALLOW DEPTH EFFICIENCY CLARITY


Download ppt "1 Introduction to Recursion Please fasten your seat belts."

Similar presentations


Ads by Google