Recursion and Recursive Algorithms
Recursion and Recursive Algorithms
RECURSIVE
ALGORITHMS
Dr. Paul Aazagreyir,( Ph.D., MSc, BSc)
LECTURE OBJECTIVES
By the end of this lecture, you will be able to
Factorial Example
Purpose of Recursions
Direct Recursion
Indirect Recursion
Reversing an Array
Fibonacci Sequence
Recursion and Recursive Algorithms
(Definitions)
Recursion is the process of defining something in terms of itself.
And which obtains the result for the current input by applying simple operations
to the returned value for the smaller (or simpler) input.
MAIN INSTANCES OF RECURSION TECHNIQUES
Recursive technique (i.e. when recursion is used as a technique in which a
function makes one or more calls to itself).
Data structure technique(i.e. when a data structure uses smaller instances of the
exact same type of data structure when it represents itself).
USES OF RECURSION
Recursion provides an alternative for performing repetitions of the task in which
a loop is not ideal. Most modern programming languages support recursion.
Recursion serves as a great tool for building out particular data structure. So
now let’s start with an example exercise of creating a factorial function.
FACTORIAL EXAMPLE
The factorial function is denoted with an exclamation point and is
defined as the product of the integers from 1 to n. Formally, we can state
this as:
n! = n ⋅ (n−1) ⋅ (n−2) … 3 ⋅ 2 ⋅ 1
Note, if n = 0, then n! = 1. This is important to take into account,
because it will serve as our base case.
Take this example:
4! = 4 ⋅ 3 ⋅ 2 ⋅ 1 = 24.
So how can we state this in a recursive manner? This is where the
concept of base case comes in.
FACTORIAL EXAMPLE CONTINUOUS
Base case is a key part of understanding recursion, especially when it
comes to having to solve interview problems dealing with recursion.
Let’s rewrite the above equation of 4! so it looks like this:
4! = 4 ⋅ (3 ⋅ 2 ⋅ 1) = 24
Notice that this is the same as:
4! = 4 ⋅ 3! = 24
Meaning we can rewrite the formal recursion definition in terms of
recursion like so:
n! = n ⋅ (n−1) !
Note, if n = 0, then n! = 1.
This means the base case occurs once n=0,
the recursive cases are defined in the equation above. Whenever you are
trying to develop a recursive solution it is very important to think about
the base case, as your solution will need to return the base case once all
the recursive cases have been worked through. Let’s look at how we can
create the factorial function in Python:
Python Code of a factorial
• def fact(n):
• '''
• Returns factorial of n (n!).
• Note use of recursion
• '''
• # BASE CASE!
• if n == 0:
• return 1
• # Recursion!
• else:
• return n * fact(n-1)
FACTORIAL EXAMPLE CONTINUOUS
Let’s see it in action! Fact (5) = 120
Note how we had an if statement to check if a base case occurred.
Without it this function would not have successfully completed running.
We can visualize the recursion with the following figure:
We can follow this flow chart from the top, reaching the base case, and
then working our way back up.
Recursion is a powerful tool, but it can be a tricky concept to implement.
FACTORIAL EXAMPLE CONTINUOUS
PURPOSE OF RECURSION
Recursive functions have many uses, but like any other kind of code, their
necessity should be considered.
As discussed above, consider the differences between recursions and loops, and
use the one that best fits your needs.
If you decide to go with recursions, decide what you want the function to do
before you start to compose the actual code.
Conditionals to Start, Continue, and Stop the Recursion
It’s important to look at any arguments or conditions that would start the
recursion in the first place.
For example, the function could have an argument that might be a string or
array.
The function itself may have to recognize the datatype versus it being recognized
before this point (such as by a parent function).
In simpler scenarios, starting conditions may often be the exact same conditions
that force the recursion to continue.
More importantly, you want to establish a condition where the recursive action
Conditionals to Start, Continue, and Stop the
Recursion continuous
These conditionals, known as base cases, produce an actual value rather than
another call to the function.
However, in the case of tail-end recursion, the return value still calls a function
but gets the value of that function right away
However, there are multiple ways to go about it, so feel free to alter the
complexity as needed.
THE THREE LAWS OF RECURSION
All recursive algorithms must obey three important laws:
A recursive algorithm must have a base case, which denotes the point when it
should stop.
A recursive algorithm must change its state and move toward the base case
which enables it to store and accumulate values that end up becoming the
answer.
A recursive algorithm must call itself, recursively with smaller and smaller values.
TYPES OF RECURSION
DIRECT RECURSION
Tail Recursion:
If a recursive function calling itself and that recursive call is the last
statement in the function then it’s known as Tail Recursion. After that
call the recursive function performs nothing. The function has to
process or perform any operation at the time of calling and it does
nothing at returning time.
TYPES OF RECURSION CONTINUOUS
Example:
// Code Showing Tail Recursion
#include <iostream>
using namespace std;
// Recursion function
void fun(int n)
{
if (n > 0) {
cout << n << " ";
// Last statement in the function
fun(n - 1);
}
TYPES OF RECURSION CONTINUOUS
// Driver Code
int main()
{
int x = 3;
fun(x);
return 0;
}
TYPES OF RECURSION CONTINUOUS
Time Complexity For Tail Recursion : O(n)
Space Complexity For Tail Recursion : O(n)
Lets us convert Tail Recursion into Loop and compare each other in
terms of Time & Space Complexity and decide which is more efficient.
// Converting Tail Recursion into Loop
#include <iostream>
using namespace std;
void fun(int y)
{
while (y > 0) {
cout << y << " ";
TYPES OF RECURSION CONTINUOUS
// Driver code
int main()
{
int x = 3;
fun(x);
return 0;
}
Time Complexity: O(n)
Space Complexity: O(1)
So it was seen that in case of loop the Space Complexity is O(1) so it
was better to write code in loop instead of tail recursion in terms of
Space Complexity which is more efficient than tail recursion.
TYPES OF RECURSION CONTINUOUS(Head Recursion)
Head Recursion:
If a recursive function calling itself and that recursive call is the first
statement in the function then it’s known as Head Recursion.
There’s no statement, no operation before the call. The function doesn’t have to
process or perform any operation at the time of calling and all
operations are done at returning time.
TYPES RECURSION CONTINUOUS(Head Recursion)
If a recursive function calling itself and that recursive call is the first
statement in the function then it’s known as Head Recursion.
There’s no statement, no operation before the call. The function doesn’t have to
process or perform any operation at the time of calling and all
operations are done at returning time.
HEAD RECURSION CONTINUOUS
Example:
// C++ program showing Head Recursion
#include <bits/stdc++.h>
using namespace std;
// Recursive function
void fun(int n)
{
if (n > 0) {
// First statement in the function
fun(n - 1);
cout << " "<< n;
}
}
// Driver code
HEAD RECURSION CONTINUOUS
int main()
{
int x = 3;
fun(x);
return 0;
}
Time Complexity For Head Recursion: O(n)
Space Complexity For Head Recursion: O(n)
Let’s convert the above code into the loop.
// Converting Head Recursion into Loop
#include <iostream>
using namespace std;
HEAD RECURSION CONTINUOUS
// Recursive function
void fun(int n)
{
int i = 1;
while (i <= n) {
cout <<" "<< i;
i++;
}
}
// Driver code
int main()
{
int x = 3;
fun(x);
return 0;
TYPES OF RECURSION CONTINUOUS(Tree Recursion)
Tree Recursion:
To understand Tree Recursion let’s first understand Linear Recursion. If a recursive function
calling itself for one time then it’s known as Linear Recursion. Otherwise if a recursive function
calling itself for more than one time then it’s known as
Tree Recursion.
Example: Pseudo Code for linear recursion
fun(n)
{
// some code
if(n>0)
{
fun(n-1); // Calling itself only once
}
// some code
TYPES OF RECURSION CONTINUOUS(Tree Recursion)
Program for tree recursion
// C++ program to show Tree Recursion
#include <iostream>
using namespace std;
// Recursive function
void fun(int n)
{
if (n > 0)
{
cout << " " << n;
// Calling once
fun(n - 1);
// Calling twice
fun(n - 1);
}
TYPES OF RECURSION CONTINUOUS(Tree Recursion)
// Driver code
int main()
{
fun(3);
return 0;
}
Output:
3211211
Time Complexity For Tree Recursion: O(2n)
Space Complexity For Tree Recursion: O(n)s
DIRECT RECURSION CONTINUOUS
/ Driver code
int main()
{
int r;
r = fun(95);
cout << " " << r;
return 0;
}
TYPES OF RECURSION CONTINUOUS(Tree Recursion)
Nested Recursion:
In this recursion, a recursive function will pass the parameter as a
recursive call. That means “recursion inside recursion”. Let see the
example to understand this recursion.
Example:
// C++ program to show Nested Recursion
#include <iostream>
using namespace std;
int fun(int n)
{
if (n > 100)
return n - 10;
// A recursive function passing parameter
// as a recursive call or recursion inside
// the recursion
return fun(fun(n + 11));
INDIRECT RECURSION
• In this recursion, there may be more than one functions and they are calling one
another in a circular manner.
INDIRECT RECURSION CONTINUOUS
INDIRECT RECURSION CONTINUOUS
}
void funB(int n)
{
if (n > 1) {
cout <<" "<< n;
// Fun(B) is calling fun(A)
funA(n / 2);
}
}
// Driver code
int main()
{
funA(20);
return 0;
} Output:
RECURSION VERSUS ITERATION
The Recursion and Iteration both repeatedly execute the set of instructions.
The iteration is when a loop repeatedly executes until the controlling condition
becomes false.
Infinite recursion occurs if the recursion step does not reduce the problem in a manner
that converges on some condition (base case) and Infinite recursion can crash the
system.
Recursion is usually slower than iteration due to the overhead of maintaining the stack
An infinite loop occurs with iteration if the loop condition test never becomes
false and Infinite looping uses CPU cycles repeatedly.
An iteration does not use the stack so it's faster than recursion.