# Chapter 8: Recursion - PowerPoint PPT Presentation

PPT – Chapter 8: Recursion PowerPoint presentation | free to view - id: fe2d-ZTE1N The Adobe Flash plugin is needed to view this content

Get the plugin now

View by Category
Title:

## Chapter 8: Recursion

Description:

### To solve the problem, break it down into a smaller version of the same problem ... Break down the smaller version into an even smaller version and solve this new ... – PowerPoint PPT presentation

Number of Views:113
Avg rating:3.0/5.0
Slides: 29
Provided by: NKU
Category:
Tags:
Transcript and Presenter's Notes

Title: Chapter 8: Recursion

1
Chapter 8 Recursion
• Recursion is based on a problem solving principle
called divide and conquer
• To solve the problem, break it down into a
smaller version of the same problem and solve the
smaller version
• How do you solve the smaller version?
• Break down the smaller version into an even
smaller version and solve this new version of the
problem
• How?
• Break this one into an even smaller problem
• This sounds too easy
• The trick is to identify how to break the problem
down and also how to solve the smallest version
of the problem

2
Simple Example Factorial
• Factorial is the value you get by multiplying an
integer by each smaller integer until you reach 1
• 5! 5 4 3 2 1
• We can solve this problem using iteration easily
• We can also solve this problem using recursion
easily by identifying the following
• factorial(x) x factorial(x 1)
• we have identified a way to solve the problem by
applying a smaller version of the problem
• if x is a positive integer, then x 1 is a
smaller positive integer, so we solve
factorial(x) by solving factorial(x 1)

int fact 1 for(int x n x 1 x--)
fact x
3
Implementing Recursion
• Recursion is implemented by simply calling the
same method within the method itself
• For instance, if we have a factorial method as
defined as follows
• public int factorial(int x)
• Then we write a recursive method which has code
that calls factorial with a smaller value for x
as in

return x factorial(x 1)
4
Infinite Recursion and a Base Case
• We have a slight problem with our implementation
of recursion and that is known as infinite
recursion
• If we call factorial(4) then the code calls
factorial(3) which calls factorial(2) which calls
factorial(1) which calls factorial(0) which calls
factorial(-1)
• When does it stop?
• Never
• We need to have a stopping point, a point where
factorial does not call itself, but returns a
value
• The stopping point is called the base case (or
base cases)
• What should our base case be for factorial?
• When the parameter is
• We add an if-else statement to make this work

5
The Recursive Factorial Method
public int factorial(int x) if(x return 1 else return x factorial(x-1)

Base case Recursive case
The iterative version public int factorial(int
x) int prod 1 for(n x n1
n--) prod n return prod
Will the two sets of code return the same
value? Try factorial(8), factorial(2), factorial(
1), factorial(0) and factorial(-5)
6
What Happens When a Method is Called?
• Before we examine why and how recursion works,
lets consider method calls in general
• When a set of code calls a method, some
interesting things happen
• A method call generates an activation record
• The activation record (AR) is placed on the
run-time stack
• ARs will store the following information about
the method
• Local variables of the method
• Parameters passed to the method
• Value returned to the calling code (if the method
is not a void type)
• The location in the calling code of the
instruction to execute after returning from the
called method

7
The Run-time Stack
• Notice that we use a stack to accumulate
activation records. Why?
• Calling methods is a LIFO activity
• Imagine that method1 calls method2 which calls
method3
1 or method2?
• method2, which was the last one we were at,
therefore LIFO
• Using a stack makes it easy to backtrack to the
proper location when a method ends

Run-time stack main calls m1 m1 calls m2 m2
calls m3 m3 calls m4 We are currently in m4
Main AR m1 AR m2 AR m3 AR m4 AR
stack pointer
8
Re-Examining Recursion
• Recursion works because of the run-time stack
• Each time a method is called, its AR is placed on
the top of the run-time stack
• When that method ends, its AR is popped off the
run-time stack thus causing the system to return
to the previous code (whatever called it)
• This allows us to backtrack
• The recursive method manipulates the data
pertaining to the problem, solving some portion
of it
• So, the chain of method calls contribute to solve
the problem
• As opposed to solving the problem through a
sequence of instructions that are executed
repeatedly by some form of loop

9
Recursion is Divide and Conquer
• In recursion, the same methods AR is placed onto
the run-time stack
• But each time, the AR contains data from a
smaller problem or a subset of the initial data
(i.e. the parameters change)
• Thus, this version of the method call is simpler
than the last
• When the base case is reached, the method does
not call itself recursively, so it terminates the
recursion
• Upon returning from the last method call, ARs are
popped off the run-time stack
• This continues until we have reached the original
method call that started the recursion

10
Factorial Example
public int factorial(int x) if(x return 1 else return x factorial(x-1)
(point p2)
Imagine that we have factorial(4)
(point p1) This places an AR on the run-time
stack for factorial with x 4, no local
immediately after factorial(4) in the
original code When executing factorial with x
4, it calls factorial with x 3 pushing a new
AR on the run-time stack
Here is the run-time stack after factorial(3) is
called from factorial
11
Factorial Continued
factorial calls itself recursively with x-1
each time, so at first, we have factorial with x
4 and it calls factorial(3) In this version
of factorial, x 3 and it calls factorial(2)
In this version of factorial, x 2 and it calls
factorial(1) In this version of factorial, x
1 which is the base case. Rather than calling
factorial(x 1), it instead returns 1
stack pointer
12
Factorial Continued
Return 12
Once we have reached the base case, we begin to
return from the set of recursive calls The base
instruction x factorial(x 1) where
factorial(x 1) 1 and x 2 causing this
method to return 2 1 2 returning to the
instruction x factorial(x 1) 3 2 so
this method returns 6 to x factorial(x
1) 4 3 so this method returns 12
Return 6
Return 2
Return 1
13
Thinking Recursively
• The key to thinking recursively is to see the
solution to the problem as a smaller version of
the same problem
• This decomposition tells you exactly how to solve
it
• except for the base case
• Then, identify the base case(s) and what the base
case(s) do
• Your recursive method will then comprise an
if-else statement where the base case returns one
value and the non-base case recursively calls the
same method with a smaller parameter or set of
data
• Note Forgetting the base case leads to infinite
recursion
• Although in fact, your code wont run forever
like and infinite loop, instead, you will
eventually run out of stack space and get a
run-time error/exception called a stack overflow

14
Other Recursive Methods Power
Determine the value of xn
public double power(double x, int n)
if(x 0 n IllegalArgumentException(x is zero and n
n) else if (x 0) return
0 else if (n 0) return 1
else if (n 0) return x
power(x, n 1) else return 1 / power(x,
-n)
Base cases if x 0 and n error (00 is undefined) otherwise if x 0 then
the product is 0 (0n 0) otherwise if n 0
then the value is 1 (x0 1) Recursive cases
power(x, n) x power(x, n 1) for n 0 and
power(x, n) 1 / power(x, -n) for n 15
Other Recursive Methods Print Linked List
public void print(IntNode x) if(x !
null) System.out.println(x.getDat
Base case if the pointer is null, then we
are at the end of the list Recursive case
otherwise, print out the data item of the
current node and recursively call the method
with the pointer to the next item in the
list printBackwards works by going to the end
of the list recursively before starting to print
each item
public void printBackwards(IntNode x)
if(x ! null) printBackwards(x.ge
))
16
When print(head) is called, an AR is placed on
the run-time stack which contains a pointer, x,
pointing at the first IntNode in the chain
Since x is not null, print out 6 and then call
print passing this nodes link field A new AR
is pushed onto the stack with a pointer x
pointing at the IntNode with 18 Since x is not
null, print out 18 and then call print passing
the nodes link field (pointer to 3) etc until
x points at 4, when print(x.getLink( )) is
called, the parameter is null, so the recursion
ends
public void print(IntNode x) if(x !
null) System.out.println(x.getDat
6 18 3
9 4
See if you can demonstrate that printBackwards
works correctly using the above linked list and
following the recursive calls
17
Other Recursive Methods Fibonacci
The Fibonacci sequence of numbers is 1, 1, 2, 3,
5, 8, 13, 21, 34, Each digit is the sum of the
previous 2 digits Compute the nth fibonacci
value Iterative method public int
fibonacci(int n) int fib1 0, fib2 0,
j, temp for(j2 j temp fib2 fib2 fib2 fib1
fib1 temp return fib2
Recursive method public int fibonacci(int n)
if(n IllegalArgumentException (n 0) else if (n 1 n 2) return
1 else return fib(n 1) fib(n 2)

18
Recursive Binary Search
Binary search are already uses a
divide-and-conquer approach so it is suitable
for recursion The idea is that the binary search
method will compute a mid point, compare the
middle item to what is being sought, and either
return the index of the mid point if the item is
the one being sought, or recursively call itself
with a smaller portion of the array
Iterative method public int binarySearch
(intArray a, int target, int n) int
first, last, middle middle (first last)
/ 2 while(target ! amiddle first last) if (target last middle 1 else if (target
amiddle) first middle 1 if
(first 1
Recursive method public int bs(intArray a, int
target, int first, int last) int middle
(first last) / 2 if (target
amiddle) return middle else if (last
amiddle) return bs(a, target,
first, middle 1) else return bs(a,
target, middle 1, last)
19
Complexity of Recursion
• So far, our determination of computational
complexity has been based on seeing how many
times a loop iterates
• With recursion, we dont have loops
• What is the complexity of a recursive method?
• It is the complexity of the method depth of
recursion
• Depth is the number of times the method is called
recursively
• Consider recursive factorial
• the method has 1 if-else statement so its
complexity is O(1) but there are n 1 recursive
calls if the original parameter is n, so the
complexity is O(1 (n 1)) O(n)
• For binary search
• The method has 1 assignment statement and a
nested if-else statement which is O(1). How many
times is the method called? In the worst case,
log n, so the complexity is O(log n) just like
the iterative version

20
Why Recursion?
• There are several significant problems with
recursion
• mostly it is hard (especially for inexperienced
programmers) to think recursively
• Why use it? It seems like there is always an
iterative solution to a problem that we can solve
recursively
• Is there a difference in computational
complexity? No
• Is there a difference in the efficiency of
execution? Yes, in fact, the recursive version
is usually less efficient because of having to
push ARs onto and pop ARs off of the run-time
stack, so iteration is quicker
• Although you might notice that the recursive
versions use fewer or no local variables

21
Why Recursion?
• The answer to our question is predominantly
because it is easier to code a recursive solution
once one is able to identify that solution
• Compare the code, the recursive code is usually
smaller, more concise, possibly even easier to
understand
• But also, there are some problems that are very
difficult to solve without recursion
• Those that require backtracking such as
• searching a maze for a path to an exit
• tree based operations (which you will see in CSC
364)
• There are also some interesting sorting
algorithms that use recursion
• we may look at these later in the semester, or
you will see them in 364

22
Tower of Hanoi
Towers with 4 disks
• This problem comes from history, monks in Viet
nam were asked to carry 64 gold disks from one
tower (stack) to another
• Each disk is of a different size
• There are 3 stacks, a source stack, a destination
stack and an intermediate stack
• A disk is placed on one of three stacks but no
disk can be placed on top of a smaller disk

How will the monks solve this problem? How
long will it take them? The easiest solution is
a recursive one
23
Solution
• The key to the solution is to notice that to move
any disk, we must first move the smaller disks
off of it, thus a recursive definition
• Move 1 disk from start tower to destination tower
• To move 2 disks
• Move smaller disk from start tower to
intermediate tower, move larger disk from start
tower to final tower, move smaller disk from
intermediate tower to final tower
• To move n disks
• Solve the problem for n 1 disks but use the
intermediate tower instead of the final tower
• Move the biggest disk from start tower to final
tower
• Solve the problem for n 1 disks but use the
intermediate tower instead of the start tower

24
The Solution Pictorially
Recursively move 3 disks using Intermediate
Start Intermediate Final
Start Intermediate Final
Start Intermediate Final
Move disk 4 from start to finish
Recursively move 3 disks using Intermediate
25
Solving the Problem with 3 Disks
In solving the problem with 4 disks, we have
to first solve the problem with 3 disks where
the 3 disks move from Start to Intermediate,
how?
Start Intermediate Final
Solve the 3 disks recursively Move the top 2
disks from Start to Final Move bottom (3rd)
disk from Start to Intermediate Move 2 disks
from Final to Intermediate How do you move 2
disks? Move top disk from Start to
Intermediate Move 2nd disk from Start to
Final Move top disk from Intermediate to Final
Start Intermediate Final
26
Towers Solution and Complexity
public void hanoi(int n, char source, char
intermediate, char destination) if (n
1) System.out.println(move disk from
source to destination) else
hanoi(n-1, source,
destination, intermediate)
System.out.println(move disk from source
to destination) hanoi(n-1,
intermediate, source, destination)
The complexity of this solution is not obvious
because this is no longer a solution in which the
recursive part calls itself once, but instead,
there are two recursive calls Lets find the
solution by considering the number of moves for n
2 hanoi(n1) println hanoi(n1) 1 1
1 3 println statements (3 disk moves) So, for
n 3 we have hanoi(n2) println hanoi(n2)
3 1 3 7 moves For n 4 we have hanoi(n3)
println hanoi(n3) 7 1 7 15 moves For
some n, we have hanoi(n-1) 1 hanoi(n-1) or 2
hanoi(n-1) 1 So, for n, the solution is twice
as much as n-1 This results in a complexity of
O(2n) how many moves will it take the monks
with n 64???
27
Tail Recursion
• Recall we could change the direction of
printing our linked list simply by altering
whether the recursion occurred before or after
the print statement
• This is also true with the factorial problem
• return x factorial(x 1)
• return factorial(x 1) x
• Tail recursion occurs when the recursive call is
at the end of the recursive instruction
• such as with the first of our factorial solutions
above
• it is useful to note when your algorithm uses
tail recursion because in such a case, the
algorithm can usually be rewritten to use
• this is not the case with head recursion, or when
the method calls itself recursively in different
places like the Tower of Hanoi solution
• although we can also remove recursion from such
cases by using our own stack and essentially
simulating how recursion would work

28
Recursion and Objects
• A potential problem with recursion in Java occurs
when you are passing Objects recursively
• Remember that if objects are pointed to by
reference variables (pointers)
list to a recursive printBackward method
• This will not cause a problem because the head
pointer itself is not being reassigned
• But instead, consider not only passing the
reference variable, but also changing the Object
that is being pointed to
• This will result in the Object or Objects in the
list being changed forever we need to avoid
this
• In some languages, it is also possible to create
lost Objects if you are not careful in passing
pointers as parameters
• In Java, this is not the case because Java does
not allow you to return an altered pointer, but
this could happen easily in C or Pascal!