0% found this document useful (0 votes)
10 views14 pages

Understanding Recursion in Python

Recursion in python

Uploaded by

suyashdubey2008
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views14 pages

Understanding Recursion in Python

Recursion in python

Uploaded by

suyashdubey2008
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

What Is Recursion in Python?

In Python, recursion refers to a function calling itself to solve a


problem. It involves two critical components:
 Base case: This is the condition that terminates the recursion. Without it, the recursive
calls would continue forever, eventually causing the function to crash or exhaust available
memory.
 Recursive case: This part of the function involves breaking down the problem into smaller
parts and calling the function again with those smaller parts.

Here is a simple way to think about recursion: imagine a function


that solves a complex problem by solving smaller versions of the
same problem, eventually reaching a solution that does require
further recursion.
The recursive approach follows the "divide and conquer" strategy,
breaking down complex problems into simpler versions until
reaching a trivial case. This approach often mirrors the way we
naturally think about solving problems. For instance, when sorting a
deck of cards, we might naturally sort smaller groups and then
combine them, which is essentially how recursive sorting algorithms
like merge sort work.
Every recursive function must have at least one base case and at
least one recursive case. The base case prevents infinite recursion
by providing a condition that does not require further function calls.
The recursive case reduces the problem size with each call,
ensuring that the base case is eventually reached.

How Does Recursion Work in Python?


Recursion works by allowing a function to call itself with modified
arguments, gradually solving the problem in smaller steps. To
understand this more concretely, consider the task of calculating
the sum of numbers from 1 to num.
Here is a simple recursive approach to calculate the sum:
def sum_recursive(num):

if num == 1: # Base case

return num

return num + sum_recursive(num - 1) # Recursive case

print(sum_recursive(3)) # 3 + 2 + 1

6
In this function, the base case is when num == 1, which stops the
recursion. Otherwise, the function calls itself with num - 1 until it
reaches the base case.
How it works step-by-step:
1. sum_recursive(3) calls sum_recursive(2).
2. sum_recursive(2) calls sum_recursive(1).
3. sum_recursive(1) returns 1 (base case).
4. Now, sum_recursive(2) can return 2 + 1 = 3, and sum_recursive(3) can return 3 + 3 = 6.

def sum_recursive(num):
if num == 1: # Base case
return num
return num + sum_recursive(num - 1) # Recursive case

print(sum_recursive(3)) # 3 + 2 + 1

explain stepwise how the above code works

The provided code defines a recursive function that calculates the sum of all natural
numbers from the given number down to 1

Step-by-Step Explanation

- The function sum_recursive(num) takes an integer num as input


- *Base Case:*
If num == 1, the function returns 1. This stops further recursion
- *Recursive Case:*
If num is greater than 1, the function returns num + sum_recursive(num - 1).
- This means the function calls itself with a smaller value until it reaches the base case

Example with sum_recursive(3)

1. *First Call:*
sum_recursive(3)
Since 3 > 1, it returns 3 + sum_recursive(2)

2. *Second Call:*
sum_recursive(2)
Since 2 > 1, it returns 2 + sum_recursive(1)

3. *Third Call:*
sum_recursive(1)
Since 1 == 1, it returns 1

Now substitute back:


- sum_recursive(2) becomes 2 + 1 = 3
- sum_recursive(3) becomes 3 + 3 = 6

Summary Table

| Step | Function Call | Result |


|---------------------|---------------------|------------------|
| First recursion | sum_recursive(3) | 3 + sum_recursive(2) |
| Second recursion | sum_recursive(2) | 2 + sum_recursive(1) |
| Base case | sum_recursive(1) |1 |
| Resolving upwards | |2+1=3 |
| Final solution | |3+3=6 |

Each function call waits for its inner call to finish, then adds its value, until the recursion
unwinds at the base case

EXAMPLE 2
Another example would be a recursive function to calculate the
power of a number:
def power(base, exponent):

if exponent == 0: # Base case

return 1

else:

return base * power(base, exponent - 1) # Recursive case

print(power(2, 3))

This code snippet defines a recursive function power(base, exponent) that calculates the result of raising base to the
power of exponent. Here's a breakdown:

 Base Case: if exponent == 0: return 1 handles the simplest scenario where any number raised to the power of 0 is
1.

 Recursive Case: else: return base * power(base, exponent - 1) reduces the problem by multiplying base with the
result of power(base, exponent - 1). This continues until the base case is reached.
 Function Call: print(power(2, 3)) calls the function with base 2 and exponent 3, calculating (2^3) which equals 8.

The code aims to recursively compute the power of a number.

Thanks! We will use your feedback to improve our experience.

Step-by-step explanation of this power function:


 power(2, 3) calls power(2, 2).
 power(2, 2) calls power(2, 1).
 power(2, 1) calls power(2, 0).
 power(2, 0) returns 1 (base case).
 Now, working backwards: power(2, 1) returns 2 * 1 = 2.
 Then power(2, 2) returns 2 * 2 = 4.
 Finally, power(2, 3) returns 2 * 4 = 8.

When a recursive function is called, each recursive call creates a


new entry on the call stack. This stack keeps track of all function
calls and their variables. When the base case is reached, the stack
begins resolving each call in reverse order, computing the final
result step by step.
Understanding this stack behavior is crucial because it explains both
the power and limitations of recursion in Python. It elegantly
preserves context but can also lead to memory issues with deep
recursion.

Common Issues: How to Fix Recursion


Errors in Python
While recursion can be a powerful tool, it is prone to a few common
issues, such as:
Exceeding maximum recursion depth
Python has a default recursion limit of 1000 calls. If a recursive
function calls itself too many times, a RecursionError will be raised.
Here’s how to fix it:
You can increase the recursion depth using [Link]().
However, this is not recommended unless necessary, as it may
cause a stack overflow.

Missing base case


A missing or incorrect base case will cause the function to recurse
infinitely, leading to a stack overflow.
To fix it, ensure that your base case is well-defined and reachable.

How to Stop Recursion in Python


The key to stopping recursion in Python is defining a proper base
case. Without it, the recursion will never end and result in an error.
For example, in the factorial function I implemented earlier, the
base case was if num == 0, which stops the recursion. In general, you
need to ensure that every recursive function has a condition under
which it terminates.
Designing effective base cases requires careful thought. Some
guidelines include:
 Identify the simplest version of the problem that can be solved directly.
 Ensure that all recursive paths eventually reach a base case.
 Test edge cases separately to verify they are handled correctly.
 Consider multiple base cases if the problem requires it.

Recursion vs. Iteration in Python


Both recursion and iteration can solve many of the same problems,
but each has its pros and cons:
 Recursion is often more elegant and easier to understand, especially for problems that
have a natural recursive structure (e.g., tree traversals, factorials, Fibonacci numbers).
 Iteration can be more efficient because it does not involve the overhead of multiple
function calls and can avoid issues related to stack overflow. Iterative solutions are usually
more memory-efficient.

When to use recursion:


 When the problem can be naturally divided into smaller subproblems.
 For problems involving hierarchical data structures, like trees.
 When the solution in recursive form is more intuitive and leads to cleaner code.
 When code readability is prioritized over performance optimization.
 When working with data of unknown depth (like parsing nested JSON or XML).

When to use iteration:


 For problems that require repetitive tasks without dividing the problem into smaller
subproblems.
 For performance-critical tasks, where deep recursion could result in high memory usage.
 When working with large datasets that might exceed the recursion limit.
 When memory usage is a primary concern.
 For problems that are naturally sequential rather than hierarchical.

Let's compare recursive and iterative implementations of the same


problem, calculating the sum of numbers from 1 to num:
Recursive:
def sum_recursive(num):

if num == 1:

return 1

else:
return num + sum_recursive(num - 1)

Iterative:
def iterative_sum(num):

total = 0

for i in range(1, num + 1):

total += i

return total

The iterative version uses a loop to accumulate the sum, while the
recursive version breaks the problem down into adding n to the sum
of numbers from 1 to num - 1. While both solutions work, the iterative
version will be more efficient for large values of num, as it does not
involve the overhead of multiple function calls.
Some problems that are naturally recursive can be transformed into
iterative solutions using a stack or queue to simulate the recursive
calls. This technique is particularly useful when dealing with tree or
graph traversals.

Practical Examples of Recursion in


Python
Recursion can be applied to a variety of interesting problems:

1. Sorting algorithms (e.g., quick sort or merge sort)


Sorting algorithms like quick sort and merge sort rely heavily on
recursion. In these algorithms, the problem is broken down into
smaller subproblems, which are sorted recursively.
Here is a simple implementation of quicksort:
def quicksort_algo(array):

if len(array) <= 1:

return array

pivot = array[len(array) // 2]

lower = [item for item in array if item < pivot]

equal = [item for item in array if item == pivot]

greater = [item for item in array if item > pivot]

return quicksort_algo(lower) + equal + quicksort_algo(greater)


array = [220, 33, 400, 150, 16]

print(quicksort_algo(array))

[16, 33, 150, 220, 400]

def quicksort_algo(array):
if len(array) <= 1:
return array
pivot = array[len(array) // 2]
lower = [item for item in array if item
< pivot]
equal = [item for item in array if item
== pivot]
greater = [item for item in array if
item > pivot]
return quicksort_algo(lower) + equal +
quicksort_algo(greater)

array = [220, 33, 400, 150, 16]

print(quicksort_algo(array))
explain the working of the above
program stepwise in detail

The provided quicksort_algo function


implements the QuickSort algorithm
using a recursive divide-and-conquer
strategy. Here's a detailed stepwise
explanation of how this program works:

### Step 1: Check Base Case


- The function checks if the input array
has 1 or fewer elements:
if len(array) <= 1: return array
If true, the array is already sorted, so it
returns as is[1][5].

### Step 2: Select Pivot


- The pivot element is chosen from the
middle of the array:
pivot = array[len(array) // 2]
For the example array [220, 33, 400,
150, 16], the pivot is 400 (element at
index 2)[1][5].

### Step 3: Partition Array


- The array is split into three sublists:
- lower: Items less than the pivot
- equal: Items equal to the pivot
- greater: Items greater than the pivot
For the array [220, 33, 400, 150, 16]
with pivot 400, this results in:
lower = [220, 33, 150, 16],
`equal = `,
greater = [] (empty since no item >
400)[1][4].

### Step 4: Recursive Calls to Sort


Sublists
- The function recursively sorts the lower
and greater sublists using the same
QuickSort method:
return quicksort_algo(lower) + equal +
quicksort_algo(greater)[1][4].

### Step 5: Recursion Unfolding with


Example
- First call: quicksort_algo([220, 33, 400,
150, 16])
- Pivot = 400
- lower =
- equal =
- greater = []
Return quicksort_algo([220, 33, 150,
16]) + + quicksort_algo([])

- Second call (sorting lower):


quicksort_algo([220, 33, 150, 16])
- Pivot = 150 (middle element)
- lower =
- equal =
- greater =
Return quicksort_algo([33, 16]) + +
quicksort_algo()

- Third call (sorting [33, 16]):


- Pivot = 16 (middle element)
- lower = []
- equal = [10]
- greater = [6]
Return quicksort_algo([]) + [10] +
quicksort_algo([6])
- Base cases:
quicksort_algo([]) returns []
quicksort_algo([6]) returns [6]

- So, [33, 16] sorts to [16, 33]

- Base cases for `` and [] return `` and []

- Combining all gives:


[16, 33] + + = [16, 33, 150, 220]

- Finally, the entire array sorts to:


[16, 33, 150, 220] + + [] = [16, 33, 150,
220, 400]

### Summary
- The function keeps dividing the array
into smaller parts around a pivot until
each part is trivially sorted (0 or 1
element)[1].
- It then combines these sorted parts to
get the full sorted list[1][4].
- Pivot selection and list comprehension
for partitioning make this
implementation clean and concise[4][5].

This is how the recursion and


partitioning in QuickSort collaboratively
sort the original array step-by-step[1]
[5].The quicksort_algo function sorts an
array using the QuickSort algorithm, a
recursive divide-and-conquer method.

Step 1: Base case - if the array has 1 or


fewer elements, it returns the array as it
is already sorted.

Step 2: Pivot selection - the function


picks the middle element of the array as
the pivot.

Step 3: Partitioning - the array is split


into three lists:
- lower: elements less than the pivot
- equal: elements equal to the pivot
- greater: elements greater than the
pivot
Step 4: Recursive sorting - it recursively
sorts the lower and greater lists by
calling quicksort_algo on them.

Step 5: Combining - it concatenates the


sorted lower list, the equal list, and the
sorted greater list, returning the fully
sorted array.

Example for array :

- Pivot = 400; lower=, equal=, greater=[]


- Recursively sort lower: pivot=150;
lower=, equal=, greater=
- Recursively sort : pivot=16; lower=[],
equal=[10], greater=[6]
- Base case reached for empty and
single-element lists
- Combine: + + =
- Combine with pivot 400: + + [] =

Thus, the algorithm recursively partitions


and sorts subarrays around pivots until
the entire array is sorted.
Conclusion
Recursion is a powerful concept in Python that helps solve complex
problems by breaking them down into simpler subproblems. When
used correctly, recursion leads to clean, concise code that is easy to
understand.
However, it is essential to define proper base cases and be mindful
of recursion depth to avoid common errors.
While recursion can sometimes be less efficient than iteration, it is
an invaluable tool for solving certain types of problems, particularly
those involving hierarchical data or problems that naturally lend
themselves to recursive solutions.

You might also like