1 Introduction to Recursion Please fasten your seat belts.
-
Upload
kellie-booth -
Category
Documents
-
view
231 -
download
0
Transcript of 1 Introduction to Recursion Please fasten your seat belts.
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
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
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
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 1RECURSION: 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 1RECURSION: x raised to y is equal x times x raised to y-1
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
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
<IntegerConstant> ::= <Digit> | <Digit><IntegerConstant><Digit> ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0<IntegerConstant> ::= <Digit> | <Digit><IntegerConstant><Digit> ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0
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 programvoid 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
"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
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 3Push Pop
11
What is a Stack?
A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in
first-out order (LIFO).first-out order (LIFO).
12
Thing 1
PUSH
A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in
first-out order (LIFO).first-out order (LIFO).
What is a Stack?
13
Thing 1
Thing 2
PUSH
What is a Stack?
A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in
first-out order (LIFO).first-out order (LIFO).
14
Thing 1
pop
What is a Stack?
A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in
first-out order (LIFO).first-out order (LIFO).
15
Thing 1
Thing 2
PUSH
What is a Stack?
A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in
first-out order (LIFO).first-out order (LIFO).
16
Thing 1
Thing 2
Thing 3
PUSH
What is a Stack?
A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in
first-out order (LIFO).first-out order (LIFO).
17
Thing 1
Thing 2
pop
What is a Stack?
A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in
first-out order (LIFO).first-out order (LIFO).
18
Thing 1
pop
What is a Stack?
A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in
first-out order (LIFO).first-out order (LIFO).
19
pop
What is a Stack?
A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in
first-out order (LIFO).first-out order (LIFO).
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 var2 var3
21
Algo var1 var2 var3
Proc_1 this_var that_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. ONLYONLY the top frame is active. All frames underneath it
are stopped.
22
Proc_1 this_var that_var
Algo var1 var2 var3
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
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
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_var7 9
4
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
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 <- 7this_one <- 171
this_var that_var other_var 9471
Print(this_one)
1
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
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 <- 88
Algo this_var that_var other_var4 7 98
29
Stack Trace Exampleprocedure 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 + 2endprocedure
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
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 - 2endprocedure
Output
Demo a b c1 2 3
1 2 3
Juggle x y z3 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
RR6
5 4
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
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
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
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
35
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
7
36
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
7
37
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //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 endifendprocedure //CountToTen
38
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
78
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
39
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
78
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
40
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
78
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
41
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
42
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
43
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=10
44
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
10CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=10
45
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
10CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=10
46
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
10CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=10
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=11
47
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
10CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=10
48
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
10CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
49
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
10CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
50
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
789
10
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 endifendprocedure //CountToTen
Now the work will happen as the frames pop off the stack!
53
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=7
54
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=7
55
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
56
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
57
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=9
58
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=9
59
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=10
60
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=10
61
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=10
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=11
62
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //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 endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=10
63
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //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 endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=9
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=10
64
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
109
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=9
65
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
109
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=9
66
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
1098
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
67
procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen
CountToTen: count=7
1098
CountToTen: count=8
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
68
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=7
10987
69
procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen
CountToTen: count=7
10987
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
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
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
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
Example Many mathematical functions are defined
recursively. For example, the factorial function:
N! = N * (N-1)! for N>0
0! = 1
We have defined factorial in terms of a smaller (or simpler) instance of itself.We must also define a base case or stopping condition.
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
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
General format formany recursive functions
if (some condition for which answer is known) // base case
solution statement
else // general case
recursive function call
SOME EXAMPLES . . .
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
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
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! = 1if n > 0, then n! = n * (n-1)!
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
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 return
address n value 3 3 * fact(2)
7
return return
address n value 2 2 * fact(1)
7
return return
address n value 1 1 * fact(0)
7
return return
address n value 0 1
84
20
return return
address n value 3 3 * fact(2)
7
return return
address n value 2 2 * fact(1)
7
return return
address n value 1 1 * fact(0)
7
return return
address n value 0 1
1 * 1
2 * 1
3 * 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
if (0 = 0) then Fact returns 1 else Fact returns 1 endifendfunction //Fact
if (0 = 0) then Fact returns 1 else Fact returns 1 endifendfunction //Fact
if (1 = 0) then Fact returns 1 else Fact returns 1 * Fact(0) endifendfunction //Fact
if (1 = 0) then Fact returns 1 else Fact returns 1 * Fact(0) endifendfunction //Factif (2 = 0)
then Fact returns 1 else Fact returns 2 * Fact(1) endifendfunction //Fact
if (2 = 0) then Fact returns 1 else Fact returns 2 * Fact(1) endifendfunction //Fact
if (3 = 0) then Fact returns 1 else Fact returns 3 * Fact(2) endifendfunction //Fact
if (3 = 0) then Fact returns 1 else Fact returns 3 * Fact(2) endifendfunction //Fact
algorithm Test ans <- Fact(3)endalgorithm
algorithm Test ans <- Fact(3)endalgorithm
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
Activation Stack for Factorial
Call the function: answer <- Fact(5)
Main Algorithm: Unfinished: answer <- Fact (5)
88
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
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
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
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
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
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
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
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
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
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
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Finished: returns 5*24
101
Can we write it recursively?
be = b * b(e-1)
What’s the limiting case?
When e = 0 we have b0 which always equals?
1
LB
102
Another Recursive Function
function Power returnsa Num(base, exp isoftype inNum)// Computes the value of BaseExp // Pre: exp is a non-negative integer if (exp = 0) then Power returns 1 else Power returns base * Power(base, exp-1) endifendfunction //Power
Power xN = x * xN-1 for N>0 x0 = 1
103
Function Power returnsa Num (base, exp isoftype in Num)//Computes the value of BaseExp
//Preconditions: exp is a non-negative integer if(exp = 0 ) then Power returns 1 else Power returns (base * Power(base, exp – 1)) endifendfunction //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)
Power base = 3 exp = 0 Finished: 11
Total <- 81
1
3
9
27
11
33
99
2727
8181
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
The PuzzleThe Puzzle
A man has an infant male-female pair A man has an infant male-female pair of rabbits in a hutch entirely of rabbits in a hutch entirely surrounded by a wall. We wish to know surrounded by a wall. We wish to know how many rabbits can be bred from this how many rabbits can be bred from this pair in one year, if the nature of the pair in one year, if the nature of the rabbits is such that every month they rabbits is such that every month they breed one other male-female pair breed one other male-female pair which begins to breed in the second which begins to breed in the second month after their birth. Assume that no month after their birth. Assume that no rabbits die during the year. rabbits die during the year.
107
ObservationsObservations
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
• snails• nautilus• other sea shells
11
2
3
5
8
13
The Occurrence in Nature…The Occurrence in Nature…
110
Fibonacci Fingers?Fibonacci Fingers?
2 hands each of which has ... 5 fingers, each of which has ... 3 parts separated by ... 2 knuckles
112
Fibonacci Numbers & SunflowersFibonacci Numbers & Sunflowers
• 34 counterclockwise• 55 clockwise
114
Fibonacci Number Sequence
if n = 1, then Fib(n) = 1if n = 2, then Fib(n) = 1if 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
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) endifendfunction //Fibonacci
117
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns Fib(3) + Fib(4)
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
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
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
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
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
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
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
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
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
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
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
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
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
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
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns 1 + 2
133
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + 3
135
Fib(5)
Fib(3)Fib(4)
Fib(3) Fib(2)
Fib(2) Fib(1)
Fib(1) Fib(0)
Fib(1) Fib(0)
Fib(2) Fib(1)
Fib(1) Fib(0)
15 calls to Fib to find the 5th Fibonacci number!!!
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
Rules of Recursion
Third fundamental rule of recursion:
“You gotta believe”: Always assume that the recursive call works.
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
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)
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
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
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
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
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
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
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
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
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
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
Recursion for Repetition
while (<condition>) <body>while (<condition>) <body>
void recWhile() { if (<condition>) <body> recWhile();}
void recWhile() { if (<condition>) <body> recWhile();}
void anotherRecWhile() { if (<condition>) AnotherRecWhile(); <body>;}
void anotherRecWhile() { if (<condition>) AnotherRecWhile(); <body>;}
An arbitrary while loop An equivalent recursive function
…Infinite recursion
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
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
struct ListType
{ int length ; // number of elements in the list
int info[ MAX_ITEMS ] ;
} ;
ListType list ;
struct ListType
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 currentelement to examine
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
“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
struct NodeType{
int info ;NodeType* next ;
}
class SortedType {public :
. . . // member function prototypes
private :
NodeType* listData ;
} ;
struct ListType
168
RevPrint(listData);
A B C D E
FIRST, print out this section of list, backwards
THEN, print this element
listData
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
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 << listPtr->info << endl ; // then print this element
}
// Base case : if the list is empty, do nothing
}170
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
found = BinarySearch(info, 25, 0, 14 );
item fromLoc toLocindexes
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
// 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
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
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.
// 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 caseresult = Func ( - a , - b ) ; // instruction 70
return result;
}
176
177
FCTVAL ? result ? b 2 a 5Return 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
FCTVAL ? result ? b 1 a 5Return Address 50
FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100
record for Func(5,2)
call in Func(5,2) codeat instruction 50 pushes on this recordfor Func(5,1)
Run-Time Stack Activation Records
x = Func(5, 2); // original call at instruction 100
179
FCTVAL ? result ? b 0 a 5Return Address 50
FCTVAL ? result 5+Func(5,0) = ? b 1 a 5Return Address 50
FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100
record for Func(5,2)
record for Func(5,1)
call in Func(5,1) codeat instruction 50pushes on this record for Func(5,0)
Run-Time Stack Activation Records
x = Func(5, 2); // original call at instruction 100
180
FCTVAL 0 result 0 b 0 a 5Return Address 50
FCTVAL ? result 5+Func(5,0) = ? b 1 a 5Return Address 50
FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return 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
FCTVAL 5 result 5+Func(5,0) = 5+ 0 b 1 a 5Return Address 50
FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100
record for Func(5,2)
record for Func(5,1)is popped nextwith its FCTVAL
Run-Time Stack Activation Records
x = Func(5, 2); // original call at instruction 100
182
FCTVAL 10 result 5+Func(5,1) = 5+5 b 2 a 5Return Address 100
Run-Time Stack Activation Records
x = Func(5, 2); // original call at line 100
record for Func(5,2)is popped lastwith its FCTVAL
183
Show Activation Records for these calls
x = Func( - 5, - 3 );
x = Func( 5, - 3 );
What operation does Func(a, b) simulate?
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.
// 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
// 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 ;
else startIndex++ ;}return found ;
}
186
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};int factorial[8] = {1, 1, 2, 6, 24, 120, 720, 5040};
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