0% found this document useful (0 votes)
16 views

CS211_3_Recursion

The document provides an overview of recursion in algorithms and data structures, detailing its definition, applications, and advantages over iterative solutions. It explains the structure of recursive methods, including base and recursive cases, and emphasizes the importance of understanding when to use recursion. Additionally, it highlights the potential inefficiencies of recursion and compares it to iteration.

Uploaded by

d865629w2z
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views

CS211_3_Recursion

The document provides an overview of recursion in algorithms and data structures, detailing its definition, applications, and advantages over iterative solutions. It explains the structure of recursive methods, including base and recursive cases, and emphasizes the importance of understanding when to use recursion. Additionally, it highlights the potential inefficiencies of recursion and compares it to iteration.

Uploaded by

d865629w2z
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 54

Algorithms & Data Structures

CS211

Recursion

Lectures 4 & 5

Samar Alsaleh
Spring 2022
04

03 Finishing Thoughts
Summary & resources

02 More about Recursion


Types, common errors, and analysis

Today’s 01 Understanding Recursion


Recursive programming, tracing, and examples

Agenda Introduction
Recursion motivation and general concept
Today’s 01

Agenda Introduction
Recursion motivation and general concept
What is Recursion?
“In order to understand recursion, one must first understand recursion.”

- Open a browser and type “recursion” on Google. Did you no ce the “Did you
mean: recursion” message?
- Click on that message. It will appear again. Click again. There it is again. Click it… OK, enough.
- “Recursion: the repeated applica on of a recursive procedure or de ni on.”
➔ Even recursion’s own de ni ons are recursive!
4
fi
ti
ti
ti
fi
ti
Recursion in Nature and More

5
How Does This Apply to Algorithms?

- In some problems, it may be be er to de ne the problem in terms of the problem


itself
- Recursion is a problem-solving approach, that leads to elegant solu ons to problems
that are di cult to solve using simple loops
- The main idea is to split a problem into one or more simpler versions of itself
6
ffi
tt
fi
ti
Recursive Algorithm

Ask

Number of people in front you:


- If there is someone in front of you, ask
Hey him/her how many people are in front of
3!
him/her
- When they respond with a value N, then
you will answer N + 1
- If there is nobody in front of you, you will
answer 0

Answer
7
Recursion In Math
- Mathema cal formulas are o en expressed recursively
- N!, for any posi ve integer N, is de ned as the product of all integers between 1 and
N inclusive:
N × N−1 × N−2 × … × 1 = N × (N−1)!

- This de ni on can be expressed recursively:


1! = 1
N! = N × (N−1)!
➔ A factorial is de ned in terms of another factorial un l the base case of 1! is reached

8
fi
ti
ti
ti
fi
ft
fi
ti
Recursion in Programming
- Recursion is a programming technique in which a method calls itself to ful ll its purpose
- When a method invokes itself, it is called a RECURSIVE METHOD
- If the method is called, it typically divides the problem into two conceptual parts:
- a part that the method knows the solu on 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 solu on
- The recursive case: a call for the recursive method but with a smaller version of the problem
- Each call sets up a new execu on 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
ti
ti
ti
fi
Recursive Method Structure
- Most recursive methods will look like:

{recursive_case
base_case → asnswer is known
recursive_alg =
→ else call me with smaller value

- Which structurally would look like:


if (some condition for which answer is known) { // base case
compute and return solution
} else { // recursive case
divide into similar subproblem(s)
solve each subproblem recursively
assemble the overall solution
}

10
Recursive Method Structure (cont.)
- But do we really need two cases?
- Let’s try a recursive logic for “coun ng down from i” with and without the base case:

Without ➔ Will run infinity!

With ➔ Will terminate when i<=1

11
ti
Why Recursion?
- For many, recursion may seem hard or impossible, however, recursion o
en provides
elegant, short algorithmic solu ons to many problems in CS and mathema cs
- For some problems recursive solu ons are o en more simple and easier to express
- Usually recursive algorithms have less code, therefore algorithms can be easier to
write and understand - e.g. Towers of Hanoi
- Some mes recursion provides a much simpler solu on. Obtaining the same result
using itera on requires complicated coding - e.g. Quicksort
- Recursive methods provide a very natural mechanism for processing recursive data
structures
- A recursive data structure is a data structure that is de ned recursively – e.g. Tree
- Recursive solu
on can be much more readable and elegant than itera ve solu on to
the same problem
12
ti
ti
ti
ti
ti
ft
ti
fi
ti
ft
ti
ti
However…
- Just because we can use recursion to solve a problem, does NOT mean we should!
- You must be able to determine when recursion is the correct technique to use
- A recursive solu on may simply be less e cient
- Furthermore, recursion has the overhead of mul ple method invoca ons, and
consequently the overhead of method calls
- Each recursive call causes another copy of the method to be created
- This set of copies can consume considerable processor me and memory space (expensive)
- Since itera on occurs within a method, repeated method calls and extra memory
assignment are avoided
- So remember,
- avoid using excessively recursive algorithms even if the code is simple
- every recursive solu on has a corresponding itera ve solu on
13
ti
ti
ti
ffi
ti
ti
ti
ti
ti
Recursion vs. Itera on

How can you nd


your hidden key?

14
fi
ti
Recursion vs. Itera on (cont.)
Itera on is a special case of recursion…
- Both itera on and recursion are based on a control statement:
- Itera on uses a repe on statement (e.g., for, while or do…while)
- Recursion uses a selec on statement (e.g., if, if…else or switch)
- Both itera on and recursion involve repe on:
- Itera on explicitly uses a repe on statement
- Recursion implicitly achieves repe on through repeated method calls
- Itera on and recursion each involve a termina on test:
- Itera on terminates when the loop-con nua on condi on fails
- Recursion terminates when a base case is reached
- Both itera on and recursion can occur in nitely:
- An in nite loop occurs with itera on if the loop-con nua on test never becomes false
- In nite recursion occurs if the recursion step does not reduce the problem each me in a
manner that converges on the base case, or if the base case is not tested
15
fi
ti
ti
ti
ti
fi
ti
ti
ti
ti
ti
ti
ti
ti
ti
ti
ti
ti
ti
ti
fi
ti
ti
ti
ti
ti
ti
ti
ti
Recursion vs. Itera on (cont.)

Iteration Recursion
repetition statement (e.g., for, selection statement (e.g., if, if…
Control statement
while or do…while) else or switch)
explicit through a repetition implicit through repeated
Repetion
statement method calls

Termination test loop-continuation condition fails base case is reached

loop-continuation test never recursion step does not converge


Infinitely
becomes false or base case is not tested

16
ti
02

Today’s 01 Understanding Recursion


Recursive programming, tracing, and examples

Agenda Introduction
Recursion motivation and general concept
Designing a Recursive Solu on
In order to design a recursive solu on, you need:
1. At least one “small” case that you can solve directly
➔ Base case
2. A way of breaking a larger problem down into one or more smaller subproblems,
each of the same kind as the original
➔ Decomposi on
3. A way of combining subproblem results into an overall solu on to the larger problem
➔ Composi on

➔ Note: All recessive solu ons require base case and decomposi on but not all require
composi on
18
ti
ti
ti
ti
ti
ti
ti
ti
Designing a Recursive Solu on (cont.)
- Let’s apply this to the problem of compu ng the factorial of a number:
‣ N! = (N − 1)! × N [for N > 1]
‣ 1! = 1
‣ 3! = 2! × 3
= (1! × 2) × 3
=1×2×3

Recursive design:
- Base case: 1!
- Decomposi on: (N − 1)!
- Composi on: × N
19
ti
ti
ti
ti
Designing a Recursive Solu on (cont.)
To verifying recursive func ons you can use the the three-ques on method:
1. Base-Case Ques on:
- Is there a non-recursive way out of the func on? i.e. What is/are the case(s) for
which you know solu on(s)?

2. Smaller-Caller Ques on:


- Does each recursive func on call involve a smaller case of the original problem
leading to the base case?

3. General-Case Ques on:


- Assuming each recursive call works correctly, does the whole func on work
correctly?

20
ti
ti
ti
ti
ti
ti
ti
ti
ti
ti
Anatomy of a Recursive Func on
- The def func on header is similar to any other func on
- Condi onal statement check for base case
- Base cases are evaluated without recursive calls
- Recursive cases are evaluated with recursive calls
- Example, a recursive method for compu ng n!:
def factorial(n): // return the factorial of n (n!)
if n == 0: // base case
return 1
else: // recursive case
return n * factorial(n-1) // composition, decomposition
21
ti
ti
ti
ti
ti
Anatomy of a Recursive Func on (cont.)
def factorial(n): // return the factorial of n (n!)
if n == 0: // base case
return 1
else: // recursive case
return n * factorial(n-1) // composition, decomposition

- This method illustrates all the important ideas of recursion:


- A base (or stopping) case
- Code rst tests for stopping condi on ( is n == 0 ?)
- Provides a direct (non-recursive) solu on for the base case (0! = 1).
- The recursive case
- Expresses solu on to problem in 2 (or more) smaller parts
- Invokes itself to compute the smaller parts, eventually reaching the base case
22
fi
ti
ti
ti
ti
When a Func on is Called…
- A transfer of control occurs from the calling
block to the code of the func on
- It is necessary that there be a return to the
correct place in the calling block a er the
func on code is executed
- This correct place is called the return address
- When any func on is called, the run- me stack
(recursion stack) is used
- An ac va on record (stack frame) is placed on
this stack for the func on call

23
ti
ti
ti
ti
ti
ti
ti
ft
ti
Stack Ac va on Frames
- The ac va on record stores:
- the return address for this func on call,
- the parameters,
- the local variables, and
- the func on’s return value, if non-void
- The ac va on record for a par cular func on call is
popped o the run- me stack when:
- the nal closing brace in the func on code is
reached, or
- the return statement is reached in the func on code
- At this me the func on’s return value, if non-void,
is brought back to the calling block return address
for use there
24
fi
ti
ti
ti
ti
f
ti
ti
ti
ti
ti
ti
ti
ti
ti
ti
ti
Recursive Tracing: Example1
- Consider the following recursive method:
public static int mystery(int n) {
mystery(648):
if (n < 10) {
return n; • int a = 648 / 10; // 64
} else { • int b = 648 % 10; // 8
int a = n / 10; • return mystery(a + b); // mystery(72)
int b = n % 10;
return mystery(a + b); mystery(72):
} • int a = 72 / 10; // 7
} • int b = 72 % 10; // 2
• return mystery(a + b); // mystery(9)
- What is the result of the following call? mystery(9):
mystery(648) • return 9;

25
Recursive Tracing: Example2
- Tracing the recursive calls of the factorial(3) on the run- me stack

26

ti
More Recursive Methods - sum()
- Consider the problem of compu ng the sum of all N N−1

∑ ∑
the integers between 1 and N, inclusive: i=N+
i=1 i=1
- If N is 5, the sum = 1 + 2 + 3 + 4 + 5 N−2


- This problem can be expressed recursively as: = N + N−1 +
The sum of 1 to N = N + the sum of 1 to N − 1 i=1
N−3
- A recursive method that computes the sum of N: = N + N−1 + N−2 +

. i=1
.
public int sum(int num) { .
if (num == 0) //base case = N + N−1 + N−2 + . . . + 2 + 1
return num;
return num + sum(num-1); //general case
}

27
ti
More Recursive Methods - sum() (cont.)
- Tracing the recursive calls of the sum method:
10 6
4 + sum(3)
main
3
3 + sum(2)
sum
sum(4) 1
2 + sum(1)
sum
sum(3)
1
sum
sum(2)

sum
sum(1)
28
More Recursive Methods - power()
- From mathema cs, we know that
0
‣ 2 =1 and 25 = 2 * 24
- In general,
0
‣ x =1 x n = x * x n−1
and
for integer x, and integer n > 0

- Here we are de ning x n recursively, in terms of x n−1:


public static int Power(int x, int n)
{
if (n == 0) // base case
return 1;
else // recursive case
return (x * Power(x, n-1));
}
29
fi
ti
More Recursive Methods - power() (cont.)
- Tracing the recursive calls of the Power method:
8 4
2 * Power(2,2)
main
2
2 * Power(2,1)
Power
Power(2,3)
1
2 * Power(2,0)
Power
Power(2,2)
1
Power
Power(2,1)

Power
Power(2,0)
30
03

02 More about Recursion


Types, common errors, and analysis

Today’s 01 Understanding Recursion


Recursive programming, tracing, and examples

Agenda Introduction
Recursion motivation and general concept
Types of Recursion
A recursive method is characterized based on:
1. Whether the method calls itself or not
- Direct vs. Indirect
2. Whether the recursion is nested or not
- Nested vs. Non-Nested
3. Whether there are pending opera ons at each recursive call
- Tail vs. Non-tail
4. Whether pending opera ons are also recursive (the shape of the calling pa ern)
- Linear(Single) vs. Tree(Mul ple)
5. Whether the method is excessively recursive or not

32
ti
ti
ti
tt
1. Direct vs. Indirect Recursion
- A method invoking itself is considered to be
direct recursion
- A method could invoke another method,
which invokes another, etc., un l eventually
the original method is invoked again
- For example, method m1 could invoke m2,
which invokes m3, which invokes m1 again
- This is called indirect recursion
- It is o en more di cult to trace and debug

33
ft
ffi
ti
1. Direct vs. Indirect Recursion (cont.)
- If a func on F calls itself (i.e F calls F), then this recursion is Direct Recursion
static int Direct(int n){
if (n<=0)
return 0;
return n + Direct(n-1);
}

- If a func on F calls G and func on G calls F, then this recursion is Indirect Recursion
static int InDirect(int n){
if (n<=0)
return 0;
return n + Buddy(n-1);
}

int Buddy(int n){


return InDirect(n);
}
34
ti
ti
ti
2. Nested and Non-Nested Recursion
- Nested recursion occurs when a method is not only de ned in terms of itself; but it is
also used as one of the parameters:
- Example: The Ackermann func on
- The Ackermann func on grows faster than a mul ple exponen al func on

public static long Ackmn(long n, long m){


if (n == 0)
return m+1;
m+1 if n = 0
else if (n > 0 && m == 0)
return Ackmn(n–1, 1); A(n, m) = A(n−1, 1) if n < 0, m = 0
else A(n−1, A(n, m−1)) other wise
return Ackmn(n–1, Ackmn(n, m–1));
}

35
ti
ti
ti
fi
ti
ti
3. Tail vs. Non-tail Recursion
- In tail recursion, a single recursive call is the
last statement to be executed in the func on
- a method is tail recursive if in each of its
recursive cases it executes one recursive call
and if there are no pending opera ons a er
that call
- In non-tail (or head) recursion, the recursive
call is not the last statement to be executed
in the func on
- Tail recursion can be replaced by itera
on to
remove recursion from the solu on as in the
next examples
36
ti
ti
ti
ft
ti
ti
3. Tail vs. Non-tail Recursion (cont.)
- It is easy to convert a tail recursive method into an itera ve 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 f2 (int n) {


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

ti
4. Linear vs. Tree Recursion
- Recursion that only contains a single self-
reference is known as linear or single recursion long factorial (int n) {
if (n == 0)
- E.g.: Factorial func on return 1;
- In the factorial func on, each invocaon of else
return n * factorial (n–1);
factorial() makes at most one new recursive call
}
- Recursion that contains mul ple self-
references is known as tree or mul ple
recursion int fib(int n){
if (n == 0 || n == 1)
- E.g.: Fibonacci func on return n;
- In the Fibonacci func on, every recursive call else
return fib(n–1) + fib(n–2);
has a pending opera on that involves another
}
recursive call

38
ti
ti
ti
ti
ti
ti
ti
ti
5. Excessive Recursion
- A recursive method is excessively recursive if it repeats computa ons for some
parameter values
- Example: The call fib(6) results in two repe
ons of fib(4). This in turn results in
repe ons of fib(3), fib(2), fib(1) and fib(0):

➔ Counting the branches, it takes 25 calls to fib() to calculate fib(6) 39


ti
ti
ti
ti
ti
Common Errors in Wri ng Recursive Methods ….……… …
There are some mistakes you should pay a en on to while wri ng recursive methods:
1. The method does not call itself directly or indirectly
2. Non-termina ng recursive methods (In nite 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!!
}

40
ti
ti
fi
tt
ti
ti
Common Errors in Wri ng Recursive Methods ….……… …
There are some mistakes you should pay a en on to while wri ng recursive methods:
1. The method does not call itself directly or indirectly se
a
2. Non-termina ng Recursive Methods (In nite recursion): rd a b
wa
- No base case: s o
t ect!
e sse orr
int badFactorial(int x) {
og r i nc
return x * badFactorial(x-1);
l pr n is
} cal rsio
ive ecu
c u rs e r
- The base case is never reached
r h parameter values:
e for, tsome
ac h ise
t e erw x) {
int anotherBadFactorial(int
a
if(x == 0) e th O th
s
returnur1; ase.
else B
e c
return x*(x-1)*anotherBadFactorial(x-2);
// When x is odd, we never reach the base case!!
}

41
ti
ti
fi
tt
ti
ti
Common Errors in Wri ng Recursive Methods (cont.). …
3. Post increment and decrement operators must not be used since the update will not
occur un l AFTER the method call - (in nite recursion)
public static int sumArray (int[ ] x, int index) {
if (index == x.length)
return 0;
else
return x[index] + sumArray (x, index++);
}

4. 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);
}
}
42
ti
ti
fi
Common Errors in Wri ng Recursive Methods (cont.). …
5. Wrong placement of return statement
- Consider the following method that is supposed to calculate the sum of the rst n integers:
public static int sum (int n, int result) {
if (n >= 0)
sum(n-1, n+result);
return result;
}

- When result is ini alized to 0, the method returns 0 for whatever value of the
parameter n
- The result returned is that of the nal return statement to be executed
- Example, a trace of the call sum(3,0) is:
sum(3,0) sum(2,3) sum(1,5) sum(0,6) sum(-1,6)

return 0 return 3 return 5 return 6


0 3 5 6
43
ti
fi
ti
fi
Common Errors in Wri ng 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:


sum(3,0) return sum(2,3) return sum(1,5) return sum(0,6) return 6

6 6 6 6

44
ti
Common Errors in Wri ng Recursive Methods (cont.). …
6. The use of instance or sta c variables in recursive methods should be avoided
- Although it is not an error, it is bad programming prac ce
- These variables may be modi ed 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);
}
}
}
45
ti
fi
ti
ti
Analyzing Recursive Algorithms
- To determine the order of a loop, we determine the order of the body of the loop
mul plied by the number of loop execu ons
- Similarly, to determine the order of a recursive method, we determine the order of
the body of the method mul plied by the number of mes the recursive method is
called
- Recursion complexity = Number of recursive calls × Body complexity
- Example, using a recursive solu on to compute the sum of integers from 1 to n, the
recursive method is invoked n mes and the method itself is O(1). So the order of the
overall solu on is O(n)

46
ti
ti
ti
ti
ti
ti
ti
Analyzing Recursive Algorithms (cont.)
Recursion Methods:
- Analyze from the inside (or deepest part) rst and work outwards
- Find the number of recursive calls and the body complexity.
- Example:
long factorial (int n) {
if (n <= 1)
• Number of recursive calls: n − 1
return 1;
else
return n * factorial (n – 1);
➡ • Body complexity: O(1)
Complexity of factorial(): O(n)
}
1 1 n−1

47
fi
When to Use a Recursive Solu on?
Shallow Depth:
- The depth of recursive calls is rela vely “shallow” compared to the size of the
problem

E ciency:
- 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 solu on

48
ffi
ti
ti
ti
04

03 Finishing Thoughts
Summary & resources

02 More about Recursion


Types, common errors, and analysis

Today’s 01 Understanding Recursion


Recursive programming, tracing, and examples

Agenda Introduction
Recursion motivation and general concept
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 de ni on 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 e cient than an itera ve solu on
The order of a recursive algorithm can be determined using techniques
similar to those used in analyzing itera ve processing
51
fi
ti
ti
ffi
ti
ti
Resources & More…
Textbooks Chapters:
- Data Structures and Algorithms in Java, Ch5
- Data Structures and Algorithm Analysis in Java, Ch1
Interesting Articles & Videos:
- Recursion in 100 Seconds
- What Is Recursion - Recursion Explained In 3 Minutes
- How Recursion Works
Credits:
- Some slides illustrative content is courtesy of Beau
Carnes, a teacher/developer with freeCodeCamp.org
52
Resources & More…

Other Resources:
- https://courses.cs.washington.edu›lectures›LectureA ›09-recursion
- Java How to Program, 9/e- Chapter 18, Recursion
- https://slideplayer.com/slide/5043474/

53
Thank You & Stay Safe
:)

You might also like