Exploring the Power of Recursion: Unraveling the Power and Applications of Recursive Algorithms

May 21, 2023 / 5 min read /

--- views

Last Updated May 21, 2023
Exploring the Power of Recursion: Unraveling the Power and Applications of Recursive Algorithms

Recursion is a fascinating concept in computer programming that may seem intimidating at first, but it's a powerful tool in the hands of a programmer.

What is Recursion?

Recursion is a way of solving a problem by breaking it down into smaller and smaller problems of the same type. The smaller problems are then solved, and the solutions are combined to solve the original problem.

Understanding Recursion

At its core, recursion involves a function calling itself repeatedly until it reaches a base case. The base case acts as a stopping condition, preventing infinite recursion, while the recursive case handles the repetitive part of the problem. By breaking down complex problems into smaller, more manageable subproblems, recursion offers an elegant approach to solving them.

A recursive function is a function that calls itself inside of its own definition. So, recursion is just another way to create a loop. But when you have a recursive function that calls itself without anything to stop it then it will become an infinite loop. If that happens the first function gets pushed on the call stack, next one on top of it and so on forever ⚠️. Or until the program throws a stack overflow error or your computer runs out of memory. To avoid this, there are 3 key things should be kept in mind while building a recursive function.

  • ArrowAn icon representing an arrow
    πŸ›‘ Base Case: Define a condition that determines when the recursion should stop. It acts as the terminating condition for the function and prevents infinite recursion.
  • ArrowAn icon representing an arrow
    πŸ”™ Return Value: Determine what the function should return in each case, including the base case and the recursive case.
  • ArrowAn icon representing an arrow
    πŸ”ƒ Recursive Call: Ensure that the function makes a recursive call to itself within the recursive case, passing appropriate arguments to progress towards the base case.

Recursion in Action

Here is a simple example of recursion. Imagine you have a list of numbers, and you want to find the sum of all the numbers in the list.

You could solve this problem using a for loop. The for loop would iterate over the list, adding each number to a running total. The running total would then be returned as the sum of the list.

However, there is another way to solve this problem using recursion. The recursive solution would work like this:

  1. ArrowAn icon representing an arrow
    If the list is empty, then the sum is 0.
  2. ArrowAn icon representing an arrow
    Otherwise, the sum is the number at the front of the list plus the sum of the rest of the list.

Here is the Python code for the recursive solution:

sum.py

1
def sum_list(list):
2
if list == []: # Base Case
3
return 0 # Return Value
4
else:
5
return list[0] + sum_list(list[1:]) # Recursive Call

If you understand both concept and code then we move on to complex stuffs.

A recursive algorithm will naturally come to mind for solving a problem defined in terms of itself. For example, take the famous Fibonacci sequence. It starts with two ones, and each subsequent number is the sum of the two previous numbers: 1, 1, 2, 3, 5, 8, 13, 21, ... so on. How do you implement a function that returns the n th Fibonacci number?

Fibonacci.py

1
def fib(n):
2
if n <= 2: # Base Case
3
return 1 # Return Value
4
return fib(n-1) + fib(n-2) # Recursive Call

The code looks simple yet it's doing some complex work under the hood. Check out this chart :

Fibonacci recursion call chart. This shows how a recursive algorithm works under the hood.
Fibonacci recursion call chart. This shows how a recursive algorithm works under the hood.

Recursion vs. Iteration

Recursive algorithms are generally simpler and shorter than iterative ones. But this simplicity comes at a price. Recursive algorithms spawn numerous clones of themselves when they run, introducing a computational overhead. The computer must keep track of unfinished recursive calls and their partial calculations, requiring more memory. And extra CPU cycles are spent to switch from a recursive call to the next and back.

In general, recursion is a good choice for problems that are naturally recursive, such as finding the factorial of a number or finding the Fibonacci sequence. Iteration is a good choice for problems that are not naturally recursive, such as finding the sum of a list of numbers or finding the maximum value in a list.

If performance must be maximized, we can avoid this overhead by rewriting recursive algorithms in a purely iterative form. Doing so is always possible. It’s a trade: the iterative code generally runs faster but it’s also more complex and harder to understand.

Reference Videos