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

1 - Recursion

The document provides an overview of recursion in programming, explaining its necessity, types, and how to construct recursive functions. It emphasizes the importance of defining base cases to prevent infinite recursion and illustrates various examples, including factorial, sum of numbers, and Fibonacci series. Additionally, it compares recursion with iteration, highlighting the advantages and disadvantages of each approach.

Uploaded by

mellaelvi23
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views

1 - Recursion

The document provides an overview of recursion in programming, explaining its necessity, types, and how to construct recursive functions. It emphasizes the importance of defining base cases to prevent infinite recursion and illustrates various examples, including factorial, sum of numbers, and Fibonacci series. Additionally, it compares recursion with iteration, highlighting the advantages and disadvantages of each approach.

Uploaded by

mellaelvi23
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 51

CEN 209 – DATA STRUCTURES

Florenc Skuka
[email protected]
LESSON 02_B

Recursion

Page 2
Course Objectives

The course objectives :


◼ To understand the need of recursion
◼ To understand how recursive functions are stored in the heap
◼ To understand the base case
◼ To be able to define base case
◼ To be able construct recursive functions
◼ To understand running times
What is recursion?

◼ When a function calls itself, this function is called a


recursive function.
◼ A recursive method solves a problem by calling a
copy of itself to work on a smaller problem. This is
called the recursion step.
◼ The recursion step can result in many more such
recursive calls.
◼ It is important to ensure that the recursion
terminates.
What is recursion?

◼There are two types of recursion


⧫ Direct recursion: A function calls itself
⧫ Indirect recursion: A function calls another, and
the other calls back this function.
What is recursion?

◼ Because a function calls itself, if not well designed,


this may go infinitely.
◼ To avoid this infinite calls the base case must be
defined.
◼ In the base case, the function is given a direct value,
and it’s provided that there is no more recursive
calls.
Why do we need recursion?

◼ Recursion is a useful technique borrowed from


mathematics.
◼ Recursive code is generally shorter and easier to write
than iterative code.
◼ Generally, loops are turned into recursive functions when
they are compiled or interpreted.
◼ Recursion is most useful for tasks that can be defined in
terms of similar subtasks. For example, sort, search, and
traversal problems often have simple recursive solutions.
Why do we need recursion?

◼ In many cases, mathematical expressions can easily


be expressed in term of themselves.
◼ As in Factorial:
n!=n ∗ (n-1)!
◼ This makes writing codes easier. And expressing
solutions become more natural.
◼ The base case needed to be described well.
Why do we need recursion?

◼ A recursive function performs a task in part by calling


itself to perform the subtasks. At some point, the
function encounters a subtask that it can perform
without calling itself.

◼ This case, where the function does not recur, is called


the base case. The former, where the function calls
itself to perform a subtask, is referred to as the
recursive case.
Format of a Recursive Function

◼ We can write all recursive functions using the format:

Page 10
Example: n! Factorial

◼ We can easily express n! = n ∗ (n-1)!;


◼ What is the base case? 1!=1;
◼ Any other case:
𝑛 ∗ (𝑛 − 1)!
◼ Then, the entire function description

𝑖𝑓 𝑛 ≤ 1 1
𝑛! =
𝑖𝑓 𝑛 > 1 𝑛* 𝑛 − 1 !
Example: n! Factorial

public long factorial(long n)


{
if (n<=1) // test for base case
return 1; // base cases: 0! = 1 and 1! = 1
else
// recursion step
return n ∗ factorial(n-1);
}
What is important?
◼ There must be (a) base case(s). in the base cases, the function
return direct result. E.g. in previous factorial question:
if (n<=1) return 1;
is the base case and it returns direct result without recursion.
◼ In every recursive call there must be a progress towards the
base cases. In factorial question, the function gets n, then it
calculates
factorial (n-1);
by calculating factorial (n-1), the function goes towards the
base case. At a point n will be (n<=1).
Recursion and Memory

◼ Each recursive call makes a new copy of that


method (actually only the variables) in memory.
◼ Once a method ends (that is, returns some data), the
copy of that returning method is removed from
memory.
◼ The recursive solutions look simple but
visualization and tracing takes time.
Recursion and Memory
◼ For better understanding, let us consider the following example.
Recursion and Memory
◼ If we call the print function with n=4, visually our memory assignments may
look like:
Recursion and Memory
◼ Now, let us consider our factorial function. The visualization of
factorial function with n = 4 will look like:
How does factorial(4) operate?

static int factorial (int n) {


if (n<=1) return 1;
int factn1 = factorial (n-1);
return n * factn1;
}
factorial(4)
n=4
factn1=?
return

res = factorial(4);
Example: factorial(4)

static int factorial (int n) {


if (n<=1) return 1;
int factn1 = factorial (n-1);
return n * factn1;
}
factorial(4) factorial(3)
n=4 n=3
factn1=? factn1=?
return return

res = factorial(4);
Example: factorial(4)

static int factorial (int n) {


if (n<=1) return 1;
int factn1 = factorial (n-1);
return n * factn1;
}
factorial(4) factorial(3) factorial(2)
n=4 n=3 n=2
factn1=? factn1=? factn1=?
return return return

res = factorial(4);
Example: factorial(4)

static int factorial (int n) {


if (n<=1) return 1;
int factn1 = factorial (n-1);
return n * factn1;
}
factorial(4) factorial(3) factorial(2) factorial(1)
n=4 n=3 n=2 n=1
factn1=? factn1=? factn1=? return 1;
return return return

res = factorial(4);
Example: factorial(4)

static int factorial (int n) {


if (n<=1) return 1;
int factn1 = factorial (n-1);
return n * factn1;
}
factorial(4) factorial(3) factorial(2)
n=4 n=3 n=2
factn1=? factn1=? factn1=1
return return return 2

res = factorial(4);
Example: factorial(4)

static int factorial (int n) {


if (n<=1) return 1;
int factn1 = factorial (n-1);
return n * factn1;
}
factorial(4) factorial(3)
n=4 n=3
factn1=? factn1=2
return return 6

res = factorial(4);
Example: factorial(4)

static int factorial (int n) {


if (n<=1) return 1;
int factn1 = factorial (n-1);
return n * factn1;
}
factorial(4)
n=4
factn1=6
return 24

res = factorial(4);
Example: factorial(4)

static int factorial (int n) {


if (n<=1) return 1;
int factn1 = factorial (n-1);
return n * factn1;
}
factorial(4)
n=4
factn1=6
return 24

res = 24;
Visualizing Recursion

• Example call
return 4 * 6 = 24 final answer

• Recursion trace recursiveFactorial (4 )

• A box for each recursive call call return 3 *2 = 6

• An arrow from each caller to recursiveFactorial (3 )


callee call return 2 *1 = 2
• An arrow from each callee to recursiveFactorial (2 )
caller showing return value
call return 1 *1 = 1

recursiveFactorial (1 )

call return 1

recursiveFactorial (0 )
Example: factorial(5)
Base case example - 2

Sum of the numbers from 1 to N


Base case example - 2

Sum of the numbers from 1 to N


◼ We can easily express :
Sum(n) = n + Sum(n-1);
◼ What is the base case?
Base case example - 2

Sum of the numbers from 1 to N


◼ We can easily express
Sum(n) = n + Sum(n-1);
◼ What is the base case?
𝑆𝑢𝑚(0) = 0;
◼Any other case:
Base case example - 2

Sum of the numbers from 1 to N


◼ We can easily express
Sum(n) = n + Sum(n-1);
◼ What is the base case?
𝑆𝑢𝑚(0) = 0;
◼ Any other case:
𝑛 + 𝑆𝑢𝑚(𝑛 − 1) ;
◼ Then, the entire function description
𝑖𝑓 𝑛 == 0 0
𝑆𝑢𝑚(1. . 𝑛) =
𝑖𝑓 𝑛 ≥ 1 𝑛 + 𝑆𝑢𝑚 1. . 𝑛 − 1 ;
Sum of the numbers from 1 to N

public int Sum( int N )


{
if( N < 1 )
return 0;
return N + Sum(N-1);
}
Base case example - 3

Display an array
◼ Show the last element. Then call the function to show the previous element in
the list.
◼ What is the base case?
if(n==0)
◼ What we do in the base case?
Show just the number and don’t recur
System.out.print(lst[N]+", ");
◼ Any other case:
System.out.print(lst[N]+", ");
Ibrahim
show(lst,N-1);
Mesecan
Page 23
Display an array

static void show(int lst[], int N )


{
System.out.print(lst[N]+", ");
if( N >=1 )
show(lst,N-1);
}
Vertical Numbers
• The static recursive method writeVertical takes one
(nonnegative) int argument, and writes that int with the
digits going down the screen one per line
✓Note: Recursive methods need not be static
• This task may be broken down into the following two
subtasks
✓Simple case: If n<10, then write the number n to the screen
✓Recursive Case: If n>=10, then do two subtasks:
• Output all the digits except the last digit
• Output the last digit
Vertical Numbers

• Given the argument 1234, the output of the first


subtask would be:
1
2
3
• The output of the second part would be:
4
Vertical Numbers

public static void writeVertical(int n) {


if (n < 10) {
System.out.println(n);
}
else //n is two or more digits long:
{
writeVertical(n/10);
System.out.println(n%10);
}
}
FindMin

𝑛= 0 𝑙𝑠𝑡[𝑛]
◼ 𝐹𝑀𝑖𝑛(𝑙𝑠𝑡, 𝑛) =
𝑛≥ 1 min(𝑙𝑠𝑡 𝑛 , 𝐹𝑀𝑖𝑛(𝑙𝑠𝑡, 𝑛 − 1)
FindMin

𝑛= 0 𝑙𝑠𝑡[𝑛]
◼ 𝐹𝑀𝑖𝑛(𝑙𝑠𝑡, 𝑛) =
𝑛≥ 1 min(𝑙𝑠𝑡 𝑛 , 𝐹𝑀𝑖𝑛(𝑙𝑠𝑡, 𝑛 − 1)

static int FndMin(int lst[], int n)


{
if (n==0)
return lst[n];
return Math.min(lst[n],FndMin(lst,n-1));
}
Fibonacci

◼ What is the base case?


if(n<=1)
◼What we do in the base case?
return n;
and don’t recur
◼Any other case:
Fib(n) = Fib(n-1) + Fib(n-2);
The Fibonacci Series

• Set of recursive calls to function fibonacci


f( 3 )

return f( 2 ) + f( 1 )

return f( 1 ) + f( 0 ) return 1

return 1 return 0
Fibonacci
static int cnt = 1;
static int Fib( int N )
{
cnt++;
if( N <= 1 ) return 1;
return Fib(N - 1) + Fib( N - 2 );
}

What is the output for the following? Why?


int res = Fib(10); int res = Fib(20);
System.out.println(cnt); System.out.println(cnt);
Output for 10: Output for (20):
177 21891
Binary Search

• Binary search uses a recursive method to search an array to


find a specified value
• The array must be a sorted array:
a[0]≤a[1]≤a[2]≤. . . ≤ a[finalIndex]
• If the value is found, its index is returned
• If the value is not found, -1 is returned
• Note: Each execution of the recursive method reduces the
search space by about a half
Binary Search

• An algorithm to solve this task looks at the middle of the


array or array segment first
• If the value looked for is smaller than the value in the middle
of the array
✓Then the second half of the array or array segment can be ignored
✓This strategy is then applied to the first half of the array or array
segment

Copyright © 2012 Pearson Addison-


11-44
Wesley. All rights reserved.
Binary Search
• If the value looked for is larger than the value in the middle of the
array or array segment
✓Then the first half of the array or array segment can be ignored
✓This strategy is then applied to the second half of the array or array segment
• If the value looked for is at the middle of the array or array segment,
then it has been found
• If the entire array (or array segment) has been searched in this way
without finding the value, then it is not in the array

Copyright © 2012 Pearson Addison-


11-45
Wesley. All rights reserved.
Pseudocode for Binary Search
Recursive Method for Binary Search
Recursion versus Iteration

Recursion:
◼ Terminates when a base case is reached.
◼ Each recursive call requires extra space on the stack frame
(memory).
◼ If we get infinite recursion, the program may run out of
memory and result in stack overflow.
◼ Solutions to some problems are easier to formulate
recursively.
Recursion versus Iteration

Iteration:
◼ Terminates when a condition is proven to be false.
◼ Each iteration does not require any extra space.
◼ An infinite loop could loop forever since there is no extra
memory being created.
◼ Iterative solutions to a problem may not always be as
obvious as a recursive solution.
Recursive or Iterative

◼ Nearly all the recursive questions can be


implemented as iterative (with loops) solutions
◼ In general, recursive algorithms are expressed easier
than iterative algorithms.
◼ There are times that you can use recursive algorithms
better without increasing the running time complexity.
◼ There are also times that recursive algorithms increase
the running time geometrically.
◼ If possible, try using iterative solutions.
Example Algorithms of Recursion

◼ Fibonacci Series, Factorial Finding


◼ Merge Sort, Quick Sort
◼ Binary Search
◼ Tree Traversals and many Tree Problems: InOrder, PreOrder
PostOrder
◼ Graph Traversals: DFS [Depth First Search] and BFS [Breadth
First Search]
◼ Dynamic Programming Examples
◼ Divide and Conquer Algorithms
◼ Towers of Hanoi

You might also like