You are on page 1of 42

RECURSION Revised 2021

1
LEARNING OUTCOMES

After the completion of this class, students should be able to:


 Explain the concept of recursion.
 Determine the base case and recursion step in a recursive algorithm.
 Write and use recursive methods.
 Demonstrate how recursive method calls are handled by the system.
 Explain the differences between recursion and iteration, and when to use each.

2
SCOPE
The concept of recursion
How to write recursive methods
Recursion vs. Iteration
Recursive methods
Common errors in writing recursive methods
Analyzing recursive algorithms

3
WHAT IS RECURSION?
In some problems, it may be better to define the problem in terms of the problem itself.
Recursion is a problem-solving approach, that leads to elegant solutions to problems that are
difficult
to solve using simple loops.
The main idea is to split a problem into one or more simpler versions of itself

4
EXERCISE
(To a student in the front row)
How many students are behind you in your
"column" in the classroom?

 You have poor vision, so you can


see only the people right next to you.
So, you can't just look back and count.

 But you can ask the person directly behind


you.

 How can we solve this problem?


(recursively )

5
THE IDEA
Recursion is all about breaking
a big problem into smaller
occurrences of that same
problem.

 Each person can solve a small part of


the problem.
 What is a small version of the problem that
would be easy to answer?
 What information from a neighbor might help
me?

6
RECURSIVE
ALGORITHM
Number of people behind me:
 If there is someone behind me,
ask him/her how many people are
behind him/her.
 When they respond with a value N, then I will
answer N + 1.

 If there is nobody behind me, I will


answer 0.

7
Mathematical formulas are often expressed
recursively. N!, for any positive integer N, is defined
as the product of all integers between 1 and N
inclusive
N * N-1 * N-2 * … * 1 = N * (N-1)!
RECURSION IN This definition can be expressed recursively:
MATH 1! = 1
N! = N * (N-1)!
A factorial is defined in terms of another factorial
until the base case of 1! is reached

8
RECURSION IN PROGRAMMING
Recursion is a programming technique in which a method calls itself to fulfill its purpose.
When a method invokes itself, it is called a RECURSIVE METHOD
If the method is called with a complex problem, it typically divides the problem into two
conceptual parts
 a part that the method knows the solution for it; and
 a part that it does not know how to solve it but rather how to get it reach the solvable part.

The code of a recursive method solves the problem using:


 The base case: a case for which we have a solution
 The recursive case: a call for the recursive method but with a smaller version of the problem

Each call sets up a new execution environment, with new parameters and new local variables
As always, when the method completes, control returns to the method that invoked it (which
may be another instance of itself).

9
RECURSIVE METHOD STRUCTURE
 Most recursive methods will look like:

if (simplest case-some condition for which answer is known-) {


compute and return solution
} else {
divide into similar subproblem(s)
solve each subproblem recursively
assemble the overall solution
}

10
DESIGNING A RECURSIVE SOLUTION
1. At least one “small” case that you can solve directly
2. A way of breaking a larger problem down into:
 One or more smaller subproblems
 Each of the same kind as the original

3. A way of combining subproblem results into an overall solution to the larger


problem

11
THREE-QUESTION METHOD OF VERIFYING
RECURSIVE FUNCTIONS
Base-Case Question: Is there a non-recursive way out of the function? i.e. What
is/are the case(s) for which you know solution(s)?

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?

12
RECURSIVE PROGRAMMING
Example: A recursive method for computing x!
long factorial (int x) {
if (x == 0)
return 1; //base case
else
return x * factorial (x – 1); //recursive case
}

This method illustrates all the important ideas of recursion:


 A base (or stopping) case
 Code first tests for stopping condition ( is x == 0 ?)
 Provides a direct (non-recursive) solution for the base case (0! = 1).
 The recursive case
 Expresses solution to problem in 2 (or more) smaller parts
 Invokes itself to compute the smaller parts, eventually reaching the base case
13
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. An activation record (stack
frame) is placed on this stack for the function call.

14
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.

15
RECURSIVE TRACING: EXAMPLE1
Consider the following recursive method:
mystery(648):
public static int mystery(int n) {
if (n < 10) { ▪ int a = 648 / 10; // 64
return n; ▪ int b = 648 % 10; // 8
} else { ▪ return mystery(a + b); // mystery(72)
int a = n / 10;
mystery(72):
int b = n % 10;
▪ int a = 72 / 10; // 7
return mystery(a + b);
▪ int b = 72 % 10; // 2
}
▪ return mystery(a + b); // mystery(9)
}
mystery(9):
 What is the result of the following call? ▪ return 9;

mystery(648)

16
RECURSIVE TRACING: EXAMPLE2
Tracing the recursive calls of the factorial(3) on the run-time stack

17
MORE RECURSIVE METHODS- SUM()
Consider the problem of computing the sum of all the integers between 1 and N, inclusive:
If N is 5, the sum = 1 + 2 + 3 + 4 + 5
This problem can be expressed recursively as:
The sum of 1 to N = N plus the sum of 1 to N-1
A recursive method that computes the sum of N :

public int sum(int num)


{
if (num == 0)
return num;
return num + sum(num-1);
}

18
EXAMPLE- SUM() - CONT.
Tracing the recursive calls of the sum method

19
MORE RECURSIVE METHODS- POWER()
From mathematics, we know that
20 = 1 and 2 5 = 2 * 24 public static int Power ( int x, int n )
In general, {
if ( n == 0 )
x0 = 1 and xn = x * xn-1 return 1; // base case
for integer x, and integer n > 0.
else // general case
return ( x * Power ( x , n-1 ) ) ;
Here we are defining xn recursively, in }

terms of xn-1

20
WHY RECURSION?
For many, recursion may seem hard or impossible, however, recursion often provides elegant,
short algorithmic solutions to many problems in computer science and mathematics.
 Usually recursive algorithms have less code; therefore, algorithms can be easier to write and
understand - e.g., Towers of Hanoi.

 Sometimes recursion provides a much simpler solution. Obtaining the same result using
iteration requires complicated coding - e.g., Quicksort and Towers of Hanoi.

21
WHY RECURSION? CONT.
 Recursive methods provide a very natural mechanism for processing recursive data
structures.

 A recursive data structure is a data structure that is defined recursively – e.g., Tree.

 Recursive solution can be much more readable and elegant than iterative solution to the same
problem.

However, avoid using excessively recursive algorithms even if the code is simple.

22
Both iteration and recursion are based on a control
statement:

RECURSION VS.  Iteration uses a repetition statement (e.g., for, while or


do…while)
 Recursion uses a selection statement (e.g., if, if…else or switch)
ITERATION Both iteration and recursion involve repetition:
 Iteration explicitly uses a repetition statement
 Recursion achieves repetition through repeated method calls

23
Iteration and recursion each involve a termination test:
 Iteration terminates when the loop-continuation condition fails

RECURSION VS.  Recursion terminates when a base case is reached.

Both iteration and recursion can occur infinitely:


ITERATION-  An infinite loop occurs with iteration if the loop-continuation test
never becomes false
CONT.  Infinite recursion occurs if the recursion step does not reduce the
problem each time in a manner that converges on the base case,
or if the base case is not tested.

24
Recursion repeatedly invokes the mechanism, and
consequently the overhead, of method calls.
 Can be expensive in terms of both processor time and memory

RECURSION VS. space.

Each recursive call causes another copy of the method


ITERATION - (actually, only the method’s variables, stored in the
activation record) to be created
CONT.  this set of copies can consume considerable memory space.

Since iteration occurs within a method, repeated


method calls, and extra memory assignment are
avoided.

25
Linear(Single) vs. Tree(Multiple)

TYPES OF Direct vs. Indirect


Nested vs. Non-Nested
RECURSION Tail vs. Non-tail

26
Recursion that only contains a single self-reference is
known as linear or single recursion. E.g.: Factorial
function
In the factorial function, each invocation of
TYPES OF factorial() makes at most one new recursive call

RECURSION: Recursion that contains multiple self-references is


known as tree or multiple recursions. E.g.: Fibonacci
LINEAR VS. TREE function

RECURSION In the Fibonacci function, every recursive call has


a pending operation that involves another
recursive call

27
EXCESSIVE RECURSION
A recursive method is excessively
recursive if it repeats computations
for some parameter values.

Example: The call fib(6) results in two


repetitions of f(4). This in turn results
in repetitions of fib(3), fib(2), fib(1)
and fib(0):

28
IF a Function F calls itself. (i.e.) F calls F. Then this
recursion is Direct Recursion.

TYPES OF
static int Direct (int n){
if (n<=0)
return 0;

RECURSION: }
return n + Direct (n-1);

DIRECT VS. IF a Function F calls G. and Function G calls F. Then this


INDIRECT recursion is Indirect Recursion.
static int InDirect (int n){

RECURSION if (n<=0)
return 0;
return n + Buddy (n-1);
}

int Buddy (int n){


return InDirect (n);
}

29
NESTED AND NON-NESTED RECURSIVE METHODS
Nested recursion occurs when a method
is not only defined in terms of itself; but
it is also used as one of the parameters:
Example: The Ackerman function
 The Ackermann function grows faster than a
multiple exponential function. public static long Ackmn(long n, long m){
if (n == 0)
return m + 1;
else if (n > 0 && m == 0)
return Ackmn(n – 1, 1);
else
return Ackmn(n – 1, Ackmn(n, m – 1));
}

30
In tail recursion, a single recursive call is the last
statement to be executed in the function.
TYPES OF In non-tail recursion, the recursive call is not the last
RECURSION: statement to be executed in the function.

TAIL VS. NON- Tail recursion can be replaced by iteration to remove


recursion from the solution as in the next example.
TAIL RECURSION

31
CONVERTING TAIL-RECURSIVE METHOD TO
ITERATIVE
It is easy to convert a tail recursive method into an iterative one:
Tail recursive method Corresponding iterative method
public static void f1(int n) {
public static void f1(int n) {
System.out.print(n + " ");
for( int k = n; k >= 0; k--)
if (n > 0)
System.out.print(k + " ");
f1(n - 1);
}
}

public static void f3 (int n) {


public static void f3 (int n) { while (n > 0) {
if (n > 6) { if (n > 6) {
System.out.print(2*n + " "); System.out.print(2*n + " ");
f3(n – 2); n = n – 2;
} else if (n > 0) { } else if (n > 0) {
System.out.print(n + " "); System.out.print(n + " ");
f3 (n – 1); n = n – 1;
} }
} }
}

32
COMMON ERRORS IN WRITING RECURSIVE
METHODS- CONT.
The method does not call itself directly or indirectly.
Non-terminating Recursive Methods (Infinite recursion):
 No base case.
int badFactorial(int x) {
return x * badFactorial(x-1);
}

 The base case is never reached for some parameter values.


int anotherBadFactorial(int x) {
if(x == 0)
return 1;
else
return x*(x-1)*anotherBadFactorial(x -2);
// When x is odd, we never reach the base case!!
}

33
COMMON ERRORS IN WRITING RECURSIVE
METHODS- CONT.
Post increment and decrement operators must not be used since the update will not occur until AFTER the
method call - infinite recursion. public static int sumArray (int[ ] x, int index) {
if (index == x.length)return 0;
else
return x[index] + sumArray (x, index++);
}
Local variables must not be used to accumulate the result of a recursive method. Each recursive call has its
own copy of local variables.
public static int sumArray (int[ ] x, int index) {
int sum = 0;
if (index == x.length)return sum;
else {
sum += x[index];
return sumArray(x,index + 1);
}
}

34
COMMON ERRORS IN WRITING RECURSIVE
METHODS- CONT.
Wrong placement of return statement.
Consider the following method that is supposed to calculate the sum of the first n integers:
public static int sum (int n, int result) {
if (n >= 0)
sum(n - 1, n + result);
return result;
}

When result is initialized to 0, the method returns 0 for whatever value of the parameter n. The result
returned is that of the final return statement to be executed. Example: A trace of the call sum(3, 0) is:

35
COMMON ERRORS IN WRITING RECURSIVE
METHODS- CONT.
A correct version of the method is:
public static int sum(int n, int result){
if (n == 0)
return result;
else
return sum(n-1, n + result);
}

Example: A trace of the call sum(3, 0) is:

36
COMMON ERRORS IN WRITING RECURSIVE
METHODS- CONT.
The use of instance or static variables in recursive methods should be avoided.
Although it is not an error, it is bad programming practice. These variables may be
modified by code outside the method and cause the recursive method to return
wrong result.
public class Sum{
private int sum;

public int sumArray(int[ ] x, int index){


if(index == x.length)
return sum;
else {
sum += x[index];
return sumArray(x,index + 1);
}
}
}

37
ANALYZING RECURSIVE ALGORITHMS
To determine the order of a loop, we determine the order of the body of the loop
multiplied by the number of loop executions
Similarly, to determine the order of a recursive method, we determine the order of
the body of the method multiplied by the number of times the recursive method is
called
Example. Using a recursive solution to compute the sum of integers from 1 to N, the
recursive method is invoked N times and the method itself is O(1). So, the order of the
overall solution is O(n)

38
WHEN TO USE A RECURSIVE SOLUTION?
SHALLOW DEPTH: The depth of recursive calls is relatively “shallow” compared to the
size of the problem.

EFFICIENCY: The recursive version does about the same amount of work as the non-
recursive version. However, it may cause a higher overhead.

CLARITY: The recursive version is shorter and simpler than the non-recursive solution.

39
SUMMARY
◼ Recursion is a programming technique in which a method calls itself. A key to being able to program
recursively is to be able to think recursively.
◼ Any recursive definition must have a non-recursive part, called the base case, which permits the
recursion to eventually end (terminate).
◼ Each recursive call to a method creates new local variables and parameters.
◼ A careful trace of recursive processing can provide insight into the way it is used to solve a problem.
◼ Recursion is the most elegant and appropriate way to solve some problems, but for others it may be
less efficient than an iterative solution.
◼ The order of a recursive algorithm can be determined using techniques similar to those used in
analyzing iterative processing.

40
REFERENCES
◼ https://courses.cs.washington.edu›lectures›LectureA ›09-recursion

◼ Java How to Program, 9/e- Chapter 18, Recursion

◼ https://slideplayer.com/slide/5043474/

41
ANY QUESTION???

You might also like