Title: Recursion
1Recursion
- What is recursion?
-
- In the context of a programming language - it
is simply an already active method (or
subprogram) being invoked by itself directly or
being invoked by another method (or subprogram)
indirectly.
2Types of Recursion
- Direct Recursion
- procedure Alpha
- begin
- Alpha
- end
- Indirect (or Mutual) Recursion
- procedure Alpha
- begin
- Beta
- end
- procedure Beta
- begin
- Alpha
- end
- Difficult in some programming languages because
of forward reference.
3Illustration
- Suppose we wish to formulate a list of
instructions to explain to someone how to climb
to the top of a ladder. - Consider the following pseudo-code statements -
- Iterative statements
Recursive statements -
procedure Climb_Ladder begin for (i 0 i lt
numRungs i) move up one rung end
procedure Climb_Ladder begin if (at top)
//the escape mechanism then stop
else begin move up one rung
Climb_Ladder end end
4Why use recursion?
- There is a common belief that it is easier to
learn to program iteratively, or to use
nonrecursive methods, than it is to learn to
program recursively. - Some programmers report that they would be
fired if they were to use recursion in their
jobs. - In fact, though, recursion is a method-based
technique for implementing iteration.
5Hard to argue conclusively for recursion!
- However, recursive programming is easy once one
has had the opportunity to practice the style. - Recursive programs are often more succinct,
elegant, and easier to understand than their
iterative counterparts. - Some problems are more easily solved using
recursive methods than iterative ones.
6Example Fibonacci Numbers
F0 F1 F2 F3 F4 F5 F6 F7
0 1 1 2 3 5 8 13
- Fibonacci numbers have an incredible number of
properties that crop up in computer science. - There is a journal, The Fibonacci Quarterly,
that exists for the sole purpose of publishing
theorems involving Fibonacci numbers. - Examples
- 1. The sum of the squares of two consecutive
Fibonacci numbers is another Fibonacci number. - 2. The sum of the first n Fibonacci numbers is
one less than Fn2 - Because the Fibonacci numbers are recursively
defined, writing a recursive procedure to
calculate Fn seems reasonable. - Also, from my earlier argument, we should
expect the algorithm to be much more elegant and
concise than an equivalent iterative one. - Consider an iterative solution!
7Non-recursive Fibonacci Numbers
-
- private static int fibonacci(int n)
-
- int Fnm1, Fnm2, Fn
- if (n lt1)
- return n //F0 0 and F1
1 - else
-
- Fnm2 0
- Fnm1 1
- for (int i 2 i lt n
i) -
- Fn Fnm1
Fnm2 - Fnm2 Fnm1
- Fnm1 Fn
-
- return Fn
-
-
Note F0 0 F1 1 F2 1 F3 2 F4 3 .
. .
8Fibonacci Numbers
- Recursive Definition
- Fib(n)
-
- Series 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...
- Java
- int fib(int n)
-
- if (n 0)
- return 0
- else if (n 1)
- return 1
- else return( fib(n-1) fib(n-2))
-
9The underlying problem with the recursive method
is that it performs lots of redundant
calculations.
Example on a reasonably fast computer, to
recursively compute F40 takes almost a minute. A
lot of time considering that the calculation
requires only 39 additions. Example to compute
F5 F5 F4 F3
F3 F2 F2 F1 F2 F1 F1 F0
F1 F0 F1 F0 It turns out
that the number of recursive calls is larger than
the Fibonacci number were trying to calculate -
and it has an exponential growth
rate. Example n40, F40 102,334,155 The
total number of recursive calls is greater than -
300,000,000
REDUNDANT!!
10History of Fibonacci Numbers
- The origin of the Fibonacci numbers and their
sequence can be found in a thought experiment
posed in 1202. It was related to the population
growth of pairs of rabbits under ideal
conditions. The objective was to calculate the
size of a population of rabbits during each month
according to the following rules (the original
experiment was designed to calculate the
population after a year) - 1. Originally, a newly-born pair of rabbits, one
male and one female, are put in a field. - 2. Rabbits take one month to mature.
- 3. It takes one month for mature rabbits to
produce another pair of newly-born rabbits. - 4. Rabbits never die.
- 5. The female always produces one male and one
female rabbit every month from the second month
on.
11Rabbit Genealogical Tree
12Solving Problems
- We encourage students to solve large problems
by breaking their solutions up into smaller
problems - These smaller problems can then be solved and
combined (integrated) together to solve the
larger problem. - Referred to as Stepwise Refinement,
Decomposition, Divide-and-conquer
13Basis of Recursion
- If the subproblems are similar to the original --
then we may be able to employ recursion. - Two requirements
- (1) the subproblems must be simpler than
the original problem. - (2) After a finite number of subdivisions, a
subproblem must be encountered that can be
solved outright.
14How is memory managed?
- Consider the following Java program
- public class MemoryDemo
-
- int I, J, K
- public static void main(String args)
-
- . . .
- three()
- . . .
-
- private static void one
-
- float X, Y, Z
-
- . . .
- return
- Say that the main program MemoryDemo has invoked
method three, three has invoked two, and two has
invoked one. - Recall that parameters and local variables are
allocated memory upon entry to a method and
memory is deallocated upon exit from the method . - Thus, the memory stack would currently look like
- Activation Records
---Available space ---
One
X
Y
Z
Two
B
C
D
Three
P
Q
R
MemoryDemo
I
J
K
15Is memory managed differently for recursion?
- No!!
- Consider the following Java program
- public class MemoryDemo
-
- int I, J, K
- public static void main(String args)
-
- . . .
- recursiveOne()
- . . .
-
- private static void recursiveOne()
-
- float X,Y,Z
- . . .
- Parameters and local variables are still
allocated memory upon entry to a method and
deallocated upon exit from the method. - Thus, during the recursion, the memory stack
would look like
16Observation!
- Some escape mechanism must be present in the
recursive method (or subprogram) in order to
avoid an infinite loop. - Iterative methods (with infinite loops) are
terminated for exceeding time limits. - Recursive methods (with infinite loops) are
terminated due to memory consumption.
17Iteration
Entry
Initialization
Decision
Done
Return
Not Done
Computation
Update
18Recursion
19Consider an Example(Summing a series of integers
from 1 to n)
public class SumDemo public static void
main(String args) int sum int n
10 // could have user input sum
iterativeSum(n) System.out.println("Sum "
sum) private static int iterativeSum(int
n) int tempSum n while ( n gt 1)
n-- tempSum n //tempSum
tempSum n return (tempSum)
public class SumDemo public static void
main(String args) int sum int n
10 //could have user input this sum
recursiveSum(n) System.out.println("Sum "
sum) private static int recursiveSum(int
n) if (n lt 1) return n
else return ( n recursiveSum(n-1))
20Formal Representation Methods
- Used by computer scientists for producing a
mathematically rigorous representation of a set
of user requirements. - Two classes of Representation Methods
- State oriented notations
- Examples (Decision Tables, Finite-state Machines)
- Relational notations
- Examples (Recurrence Relations, Algebraic Axioms)
21Using representation notations Recall the
earlier example of summing the integers from 1
to n
- This can be described as a series using the
following representation - Sum n (n-1) (n-2) ... 1 or
-
- Alternatively, recursive definitions (recurrence
relations) can be employed - Sum(n)
22Consider another example -
- Computing Factorials
- Definitions
- Iterative
- n!
- Recursive
- n!
- Java
-
public int factorial(int n) if (n 0)
return 1 else return ( n
factorial(n-1))
23Computing a power (xn)
- Recall that standard Java does not provide an
exponentiation operator the method pow in the
Math class must be used (e.g., Math.pow(2,3)) - Calculating powers can also be done using the
relationship - xn exp(n ln(x))
- Could also be done recursively
- Recursive Definition power(x,n)
- Java
-
public float power(double x, int n if (n
0) return 1.0 else if (n 1)
return x else return ( x
power(x,n-1))
24Summing the elements of an array named List that
contains n values.Assuming lower bound of 0 as
for Java
- Recursive definition
- Sum(list,n)
- Java
- //note non-primitive parameters are passed
by reference in java - the array is not
duplicated. Might be in other languages.
public int sumArray(int list, int n) //
list is the array to be summed n represents the
number //of elements currently in the
array if (n 1) return list0
else return (listn-1 sumArray(list,n-1))
25Using Scope!
- Java
- public int sumArray(int n)
-
- // access the array (in this case list) to
be - // summed through scope n represents the
number of - // elements currently in the array
- if (n 1)
- return list0
- else return (listn-1 sumArray(n-1))
-
- //in languages where parameters are duplicated
access - // arrays through scope
26Sequentially search the elements of an array for
a given value(known to be in the array)
- Recursive Definition -
- Search(List, i, Value)
- Note (1) Assumes that the desired Value is in
the array, - (2) Initial call is positionOfValue
Search(list,0,Value) - (3) Returns the array position if Value is
found in the array - Java
-
-
-
- public int search(int List, int i, int Value)
-
- if (Listi Value)
- return i
- else return Search(List,i1,Value)
-
27Sequentially search the elements of an array for
a given value(may not in the array)
- Recursive Definition -
- Search(List,i,value,numEls)
- Note (1) Assumes that the desired value may not
be in the array, returns -99 is not - (2) Initial call is positionOfValue
Search(list,0,value,numEls) - (3) numEls is the number or elements in
the array (its size) - Java
-
-
-
public int search(int List, int i, int value,
int numEls) if (Listi value)
return i else if (i numEls)
return -99 else
return Search(List,i1,value,numEls)
28Other Examples
- Reversing a character string passed as parameter
s -
-
- Converting an integer value to binary -
-
-
public void reverse (String s) char t
s.charAt(0) if (s.length() gt 1)
reverse(s.substring(1,s.length()))
System.out.print(t)
private static void convertToBinary(int x)
int t x/2 // integer divide, truncate
remainder if (t ! 0) convertToBinary
(t) System.out.print(x 2)
29Another Example
- A boolean method that checks to see if two arrays
passed as parameters are identical in size and
content (n is the size of the array). -
- areIdentical(x,y,n)
-
public boolean areIdentical(int x, int y, int
n) if (x.length ! y.length)
return false else if (n 1)
return (x0 y0) else if (xn-1 !
yn-1) return false else return
areIdentical(x,y,n-1)
30Palindromes
- Consider the following assume no mixed case
-
-
boolean is_palindrome(String s) // separate
case for shortest strings if (s.length() lt 1)
return true // get first and last
character char first s.charAt(0) char last
s.charAt(s.length()-1) if (first
last) //substring(1,s.length(0-1)
returns a string //between 1st and length-1
(not inclusive) String shorter
s.substring(1, s.length()-1) return
is_palindrome(shorter) else return
false
31Still Another Example
- What does the following java method do?
-
-
- public int whoKnows(int x, int n)
-
- if (n 1)
- return x0
- else
- return Math.min(xn-1, whoKnows(x,
n-1)) -
32Traversing a Sequential Linked List
- Iteratively method invoked by -
traverseList(p) - Algorithm traverseList(Node t)
- Node temp t
- while (temp ! null)
-
- visit (temp.data())
- temp temp.next() //move to next node
-
- return
- Recursively method invoked by -
traverseList(p) - Algorithm traverseList(Node t)
- if (t ! null)
-
- visit (t.data())
- traverseList(t.next)
-
- return
33Reversing Nodes in a null-terminated Sequential
Linked List
Iteratively method invoked by - p
reverseList(p) Algorithm reverseList(Node t)
returns Node Node p t Node q null
while (p ! null) r q q
p p p.next q.next r
return q
- Recursively method invoked by - p
reverseList(p,null) - Algorithm reverseList(Node x, Node y) returns
Node - Node t
- if (x null)
- then return y
- else
- t reverseList(x.next, x)
- x.next y
- return t
-
34More Linked List Examples
- Algorithm to copy a linked list
-
public Node copyList (Node p) Node q q
null if (p ! null) q new
Node() q.data p.data q.link
copyList(p.link) return q
- public boolean identicalLists (Node s, node t)
-
- boolean x false
- if ((s null) (t null))
- return (true)
- else if ((s ! null) (t ! null))
-
- if (s.data t.data)
- x true
- else x false
- if (x)
- return (identicalLists(s.link, t.link)
-
35Linked List Examples
- Algorithm to count the number of nodes in a
linked list -
-
- Other applications
- Traversing non-linear data structures (trees)
- Sorting (Quicksort, etc.)
- Searching (Binary search)
- public int countNodes (Node s)
-
- if (s ! null)
- return ( 1 countNodes(s.next)
- else
- return 0
-
36Mutual Recursion
- Definition a form of recursion where two
mathematical or computational objects are defined
in terms of each other. Very common in some
problem domains, such as recursive descent
parsers. - Example
function1() //do something f2()
//do something function2() //do
something f1() //do something
37Mutual Recursion
- A standard example of mutual recursion
(admittedly artificial) is determining whether a
non-negative integer is even or is odd. Uses two
separate functions and calling each other,
decrementing each time. - Example
boolean even( int number ) if( number 0
) return true else return
odd(Math.abs(number)-1) boolean odd( int
number ) if( number 0 ) return
false else return even(Math.abs(number)-
1)
38Mutual Recursion
- A contrived, and not efficient at all, example of
calculating Fibonacci numbers using mutual
recursion - Example
int Babies(int n) if(n1) return
1 else return Adults(n-1) int
Adults(int n) if(n1) return
0 else return Adults(n-1)
Babies(n-1) int Fib_Mutual_Rec(int
n) return Adults(n) Babies(n) // return
Adults(n1) // is also valid // return
Babies(n2) // is also valid
39Primitive Recursion vs Non-primitive Recursion
- All examples that we have seen to this point have
used primitive recursion. - Non- primitive recursion
-
- Ackerman(m,n)
40Pitfalls of Recursion
- Missing base case failure to provide an escape
case. - No guarantee of convergence failure to include
within a recursive function a recursive call to
solve a subproblem that is not smaller. - Excessive space requirements - a function calls
itself recursively an excessive number of times
before returning the space required for the task
may be prohibitive. - Excessive recomputation illustrated in the
recursive Figonacci method which ignors that
several sub-Fibonacci values have already been
computed.
41Disadvantages of Recursion
- Method calls may be time-consuming.
- Recursive methods may take longer to run.
- More dynamic memory is used to support recursion.