Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 23

Understanding Recursion: Base Cases and Recursive Steps

Recommended resources

Hello! Welcome to the fifth module of our course.

In the previous modules, we focused heavily on iterative techniques like two-pointers and sliding windows. These methods involve using loops to move through data structures. Now, we're going to make a significant shift and explore a completely different, yet powerful, problem-solving paradigm: recursion.

This new way of thinking might feel a bit abstract at first, but it's fundamental to many advanced algorithms and data structures, especially in trees and graphs, which we'll cover later.

Today's lesson is all about the fundamentals. Our goal is to explain the concept of recursion, identifying base cases and recursive steps. By the end of this lesson, you'll understand what it means for a function to call itself and the essential components that make recursion work correctly.

1. The Core Idea: Solving a Problem with Itself

Imagine you're the last person in a long queue, and you need to find out your position. Instead of walking to the front and counting everyone, you could simply ask the person in front of you, "What's your position?" If you know their position is, say, 10, then you know your position is 11.

But how does that person know their position? They do the same thing: they ask the person in front of them. This process repeats all the way to the very first person in the queue, who knows their position is 1. Once they state their position, the answer is passed back up the line, with each person adding 1, until it gets back to you.

This is the essence of recursion: breaking a problem down into smaller, self-similar subproblems until you reach a problem so simple that it can be solved directly.

To get a feel for this, let's watch a short segment that introduces recursion with a similar, intuitive analogy.

Simple Explanation of Recursion | Recursion Python| Data Structures & Algorithms Tutorial Python #20

The video 'Simple Explanation of Recursion' by codebasics starts with a great analogy involving a pizza queue. It illustrates how a large problem can be solved by relying on the solution to a slightly smaller version of the same problem.

Watch the first three minutes of the video (00:00 - 02:58). Focus on how Meera solves her problem by asking Shayla, and how this 'delegation' continues until it reaches someone who has a simple, direct answer.


2. The Two Pillars of Recursion

As the video hints, every recursive process relies on two critical components. A recursive function is essentially a function that calls itself.

Mastering the Art of Understanding Recursion

To formalize this, let's read a clear definition from the article 'Mastering the Art of Understanding Recursion'.

Read the section titled 'The Fundamentals of Understanding Recursion', focusing on the definitions of 'Base Case' and 'Recursive Case'.

To summarize the key points from that reading:

  1. The Recursive Step (or Recursive Case): This is where the function calls itself. The crucial detail is that it must call itself with an input that is "smaller" or "simpler" in some way, bringing it one step closer to being solved. In our queue analogy, asking the person in front of you is the recursive step. The problem becomes smaller as you move up the queue.

  2. The Base Case: This is the condition that stops the recursion. It's the simplest possible version of the problem, which doesn't require another recursive call to be solved. In our analogy, the person at the very front of the queue is the base case; they know their position is 1 without asking anyone.

What Happens Without a Base Case?

The base case is not optional. Without it, the function would call itself forever, never stopping. In programming, this doesn't actually run forever; it leads to an error.

Let's see a practical demonstration of why the base case is absolutely necessary.

What is Recursion? A Python Example

The video 'What is Recursion? A Python Example' by JomaClass gives a clear explanation of what happens when you remove the base case from a recursive function.

Watch from 11:47 to 13:17. Observe the 'maximum recursion depth exceeded' error and understand why it occurs.

This error, often called a stack overflow, happens because the computer runs out of memory to keep track of the endless chain of function calls.


3. A Concrete Example: Sum of Numbers

Let's apply these concepts to a problem you're familiar with: calculating the sum of all integers from 1 to n.

Iteratively, you'd use a loop:

def iterative_sum(n):
    total = 0
    for i in range(1, n + 1):
        total += i
    return total

How can we think about this recursively?

  • The sum of numbers up to n is simply n plus the sum of numbers up to n-1.
    • sum(n) = n + sum(n-1) --- This is our recursive step.
  • What's the simplest possible case? The sum of numbers up to 1 is just 1.
    • sum(1) = 1 --- This is our base case.

Let's see this translated into code.

Recursion in Python: Sum of Numbers from 1 to n
This image shows a Python implementation of a recursive sum function. It clearly labels the base case (`if n == 1`) and the recursive step (`n + Sum(n-1)`). The visual trace for `Sum(4)` shows how the problem is broken down until the base case is hit.

This structure is the foundation of all recursive functions: an if statement to check for the base case, and an else block that performs the recursive step.


4. Tracing the Flow: The Call Stack

How does the computer keep track of all these nested function calls, like Sum(4) calling Sum(3), which calls Sum(2), and so on? It uses a mechanism called the call stack.

Think of the call stack like a stack of plates. When a function is called, its "plate" (containing its local variables and current state) is placed on top of the stack.

  • Sum(4) is called. Its plate goes on the stack.
  • Sum(4) calls Sum(3). Sum(3)'s plate is placed on top of Sum(4)'s.
  • This continues until Sum(1) is called and its plate is placed on top.

When Sum(1) hits the base case, it returns 1. Its task is done, so its plate is removed from the top of the stack. The value 1 is passed down to the function below it, Sum(2). Now Sum(2) can finish its calculation (2 + 1 = 3) and return. Its plate is removed. This process of returning values and removing plates from the stack is called unwinding.

This "Last-In, First-Out" (LIFO) process continues until the original Sum(4) call gets its result and returns the final answer.

Watching this in a debugger makes it very clear.

Simple Explanation of Recursion | Recursion Python| Data Structures & Algorithms Tutorial Python #20

The codebasics video we saw earlier has an excellent segment where the presenter uses a debugger to step through a recursive call. This visually demonstrates the call stack in action.

Watch the section from 07:50 to 09:18. Pay close attention to the 'stack' window in the debugger. Watch how it grows as new functions are called and shrinks (unwinds) as they return.

Test your understanding!

The factorial of a non-negative integer n, denoted n!, is the product of all positive integers up to n.
For example, 5! = 5 * 4 * 3 * 2 * 1 = 120.
By mathematical convention, 0! = 1.

Based on this definition, can you identify the base case and the recursive step for a function factorial(n)?

Python Recursion: Factorial Example
This flowchart illustrates the recursive calculation of 5 factorial. It might help you visualize the steps.
Show answer

Here's how you can break it down:

  • Recursive Step: The factorial of n is n multiplied by the factorial of n-1. So, factorial(n) = n * factorial(n-1).
  • Base Case: The problem gets simpler as n decreases. The simplest case defined is 0! = 1. So, if n is 0, the function should just return 1.

The Python implementation would look like this:

def factorial(n):
    # Base Case
    if n == 0:
        return 1
    # Recursive Step
    else:
        return n * factorial(n - 1)

Conclusion

Congratulations on taking your first step into recursion! It's a fundamental concept in computer science that opens the door to solving a whole new class of problems elegantly.

Key Takeaways:

  • Recursion is a method of solving a problem where a function calls itself to solve smaller instances of the same problem.
  • Every recursive function must have two components:
    1. A base case: A stopping condition that returns a value without making another recursive call. Without it, you get infinite recursion and a stack overflow error.
    2. A recursive step: The part of the function that calls itself, but with a modified input that moves it closer to the base case.
  • The call stack is a data structure that manages the sequence of function calls, operating on a "Last-In, First-Out" (LIFO) principle.

Up Next:
Now that you understand the what and why of recursion, the next lesson will focus on the how. We will learn how to design recursive solutions for problems that can be broken down into smaller, self-similar subproblems. You'll get hands-on practice identifying the base cases and recursive steps for various classic problems.