Download presentation
Presentation is loading. Please wait.
Published byKellie Booth Modified over 9 years ago
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
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.