Week 12_ Recursion
Week 12_ Recursion
Agenda
1. Introduction to Recursion
a. What is recursion?
b. Importance of recursion in computer science
c. Basic example of recursive processes
3. Recursion Flow
4. Recursive Algorithms
a. Examples
b. Time complexity in recursive algorithms
a. What is Recursion?
It is a useful technique that makes code shorter and easier to read and write.
void recursion() {
recursion();
}
int main() {
recursion();
}
b. Importance of recursion in computer science
𝐹𝑎𝑐𝑡𝑜𝑟𝑖𝑎𝑙(𝑁) = 𝑁 ∗ 𝐹𝑎𝑐𝑡𝑜𝑟𝑖𝑎𝑙(𝑁 − 1)
𝐹𝑎𝑐𝑡𝑜𝑟𝑖𝑎𝑙(𝑁 − 1) = (𝑁 − 1) ∗ 𝐹𝑎𝑐𝑡𝑜𝑟𝑖𝑎𝑙(𝑁 − 2)
And so on.
For example:
● 5! = 5 * 4!
○ 4! = 4 * 3!
■ and so on.
This is how recursion breaks down the problem into smaller subproblems and
combines the results.
2. How Recursion Works
a. Base Case
● It defines the scenario in which the recursive function stops calling itself and
returns a specific result directly, without further recursion.
b. Recursive Case
● This process continues until the base case is reached, allowing the algorithm
to solve the problem by aggregating the results from all the recursive calls.
● In recursion, function calls create stack frames on the call stack. Each frame
represents an active function call and contains relevant information. As the
recursion progresses, stack frames are added and removed from the stack in
a Last-In-First-Out (LIFO) order. Recursive calls continue until a base case
is reached, and then the results propagate back through the stack.
● If a recursive function doesn't reach or define a base case, the recursive calls
will never stop, which will cause a stack overflow problem.
3. Recursion Flow
The recursion process begins with the first function call and continues until a base
case is reached, after which the return statement is executed to terminate the
recursion.
#include <iostream>
using namespace std;
void printNumbers(int n) {
if (n < 1) {
return;
}
printNumbers(n - 1);
cout << n << " ";
}
int main() {
printNumbers(6);
return 0;
}
Output:
1 2 3 4 5 6
Explanation:
○ Since n is not less than 1, the function calls itself with an argument of n-1,
which is 5.
○ The new call to printNumbers is made with an input value of 5 for its n
parameter.
○ Since n is not less than 1, the function calls itself again with an argument of
n-1, which is 4.
○ The new call to printNumbers is made with an input value of 4 for its n
parameter.
○ This process continues until the function call is made with an input value of
1 for its n parameter.
○ Since n is now less than 1, the function immediately returns to the previous
call.
○ The function returns to the previous call, which also executes the cout
statement and prints the value of n (which is 2) followed by a space.
○ This process continues until the function returns to the original call made by
the main function.
void printNumbers(int n) {
if (n < 1) {
return;
}
cout << n << " ";
printNumbers(n - 1);
}
The only change is the order of the cout statement and the recursive call. In this
modified version of the function, the cout statement is executed before the
recursive call, resulting in the numbers being printed in reverse order.
4. Recursive Algorithms
a. Examples
#include<iostream>
using namespace std;
int fibonacciRecursive(int n) {
if (n <= 1)
return n;
return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2);
}
int main () {
int n = 10;
cout << fibonacciRecursive(n) << endl;
return 0;
}
ii. Power Function: x^n:
#include<iostream>
using namespace std;
//Edge case
if(x == 0) return 0;
//Recursive call
return x * recursivePow(x, n - 1);
}
int main () {
int x, n;
cin >> x >> n;
cout << recursivePow(x,n);
return 0;
}
b. Time complexity in recursive algorithms
For example, let's analyze the time complexity of finding the n-th Fibonacci
number using recursion:
2. In each recursive call, the function makes two new recursive calls, which
means that the total number of calls is multiplied by 2.
3. So, the total number of times the function calls itself to find the n-th
𝑛
Fibonacci number is 2 .
That’s why, the time complexity of finding the n-th Fibonacci number using
𝑛
recursion is 𝑂(2 ).
5. Direct recursion vs Indirect Recursion
a. Direct recursion:
#include <iostream>
using namespace std;
int factorial(int n) {
if(n > 1)
return n * factorial(n - 1);
else
return 1;
}
int main() {
int num;
cin >> num;
cout << factorial(num) << endl;
return 0;
}
Working of factorial program:
b. Indirect recursion:
Indirect recursion happens when one function calls another function, and
that second function later calls the first function again. A classic example of
indirect recursion is when function A calls function B, which in turn calls
function A.
#include <iostream>
using namespace std;
void indirectRecursion2(int);
void indirectRecursion1(int n = 1){
if(n > 9)
return;
cout << n <<" ";
indirectRecursion2(n + 1);
}
void indirectRecursion2(int n = 1){
if(n > N)
return;
cout << n << " ";
indirectRecursion1(n+1);
}
int main()
{
int start = 1;
indirectRecursion1(start);
return 0;
}
6. Advantages and Disadvantages of Recursion
a. Advantages of Recursion:
Recursion can offer several benefits, such as making code more readable and
concise, increasing modularity and flexibility, reducing code duplication, and
improving the time complexity for certain problems.
b. Disadvantages of Recursion:
Disadvantages of recursion include the potential for stack overflow errors if the
recursion depth becomes too large, high memory consumption due to the
creation of new sets of variables and data for each function call, reduced
performance due to function call overhead and stack manipulation, difficulty in
debugging recursive functions, and increased code complexity.
7. Recursion VS Iteration
Recursion Iteration
Terminates when the base case Terminates when the condition
becomes true. becomes false.
Used with functions. Used with loops.
Every recursive call needs extra space Every iteration does not require any
in the stack memory. extra space.
Smaller code size. Larger code size.
8. To solve:
● Recursion: Fibonacci Numbers
● 10344 - 23 out of 5