Recursion_Recap
Recursion_Recap
● Base Case: This is the condition under which the recursive function stops calling itself.
Without a base case, the recursion would continue indefinitely, leading to a stack
overflow.
● Recursive Case: This is the part of the function where it continues to call itself with a
modified argument, gradually reducing the problem size.
Example 1: Factorial
Factorial of a number n is defined as the product of all positive integers less than or equal to n.
Mathematically, n! = n * (n-1) * (n-2) * ... * 1.
In terms of recursion:
#include <stdio.h>
int factorial(int n) {
if (n == 0 || n == 1) { // Base Case
return 1;
}
return n * factorial(n - 1); // Recursive Case
}
int main() {
int num = 5;
printf("Factorial of %d is %d\n", num, factorial(num));
return 0;
}
In terms of recursion:
#include <stdio.h>
int fibonacci(int n) {
if (n == 0) return 0; // Base Case 1
if (n == 1) return 1; // Base Case 2
return fibonacci(n - 1) + fibonacci(n - 2); // Recursive Case
}
int main() {
int num = 7;
printf("Fibonacci of %d is %d\n", num, fibonacci(num));
return 0;
}
While recursion makes the Fibonacci sequence easy to understand, it's not efficient due to
repeated calculations, which we'll discuss later.
This function adds all the digits of a given number. For example, the sum of digits of 123 is 1 + 2
+ 3 = 6.
#include <stdio.h>
int sumOfDigits(int n) {
if (n == 0) { // Base Case
return 0;
}
return (n % 10) + sumOfDigits(n / 10); // Recursive Case
}
int main() {
int num = 1234;
printf("Sum of digits of %d is %d\n", num, sumOfDigits(num));
return 0;
}
● Recursion: It’s often more elegant and concise for problems that naturally fit a recursive
structure. However, recursion can lead to higher memory usage due to the function call
stack.
● Iteration: Iterative solutions are usually more memory-efficient because they don’t
involve the overhead of multiple function calls. However, they can sometimes be less
intuitive, especially for problems like tree traversals or permutations.
Example: Factorial
Let’s compare the recursive and iterative approaches to calculating the factorial of a number.
Recursive:
int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
}
return n * factorial(n - 1);
}
Iterative:
int factorialIterative(int n) {
int result = 1;
for(int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
● Use recursion when the problem can naturally be divided into similar sub-problems.
● Avoid recursion if it leads to excessive memory use or stack overflow.
Binary Search is an efficient algorithm for finding an element in a sorted array. It works by
repeatedly dividing the search interval in half.
Algorithm:
1. Compare the target value with the middle element of the array.
2. If the target value matches the middle element, the search is done.
3. If the target value is less than the middle element, search in the left half.
4. If the target value is greater than the middle element, search in the right half.
#include <stdio.h>
int main() {
int arr[] = {2, 3, 4, 10, 40};
int n = sizeof(arr) / sizeof(arr[0]);
int x = 10;
int result = binarySearch(arr, 0, n - 1, x);
(result == -1) ? printf("Element is not present in array\n") : printf("Element is present at index %d\n",
result);
return 0;
}
#include <stdio.h>
int main() {
char str[] = "recursion";
reverseString(str, 0, sizeof(str) - 2); // -2 to exclude the null character
printf("Reversed string is %s\n", str);
return 0;
}
Finding the maximum element in an array can also be done recursively by comparing the
current element with the maximum of the rest of the array.
#include <stdio.h>
int main() {
int arr[] = {12, 10, 30, 50, 100, 40};
int n = sizeof(arr) / sizeof(arr[0]);
printf("The maximum element is %d\n", findMax(arr, n));
return 0;
}
Common Issues:
● Stack Overflow: This occurs when the recursion depth is too deep. It’s a common issue
in recursion when the base case is not properly defined or when the problem size
doesn’t reduce sufficiently with each recursive call.
● Infinite Recursion: Happens if there’s no proper base case or if the recursive case
doesn’t converge towards the base case. This leads to the function calling itself
indefinitely.
Example: In the factorial function, you can print the current value of n before each recursive call
to see the sequence of calls:
int factorial(int n) {
printf("Calling factorial(%d)\n", n);
if (n == 0 || n == 1) {
return 1;
}
return n * factorial(n - 1);
}
● Base Case Verification: Always double-check that your base case is correct and that it
will be reached in every possible execution path. This is critical for preventing infinite
recursion.
● Test with Simple Cases: Start testing your recursive functions with the simplest
possible cases (e.g., the base case) to ensure that your function handles them correctly.
● Dry Run: Manually trace through the recursive function with a small input to see if it
behaves as expected. This helps you understand how the function evolves with each
recursive call.
● Use a Debugger: If your environment supports it, use a debugger to step through the
recursive calls and examine the state of variables at each step.
Practice Problems
Problem 1: Calculate the Power of a Number
Write a recursive function to calculate the power of a number x^n. The function should take two
arguments, the base x and the exponent n.
Example:
Input: x = 2, n = 3
Output: 8
Write a recursive function to check if a string is a palindrome. A palindrome is a word that reads
the same backward as forward.
Example:
Hint: Compare the first and last characters of the string, then recursively check the substring
that excludes these characters.
Write a recursive function to find the greatest common divisor (GCD) of two numbers using
Euclid's algorithm.
Example:
Input: a = 48, b = 18
Output: 6
Example:
Output: 15
Hint: Sum the first element with the sum of the remaining elements.
Write a recursive function to generate all possible subsets of a given set of integers. This is a
classic problem often referred to as the "power set" problem.
Example:
Output: { {}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3} }
Hint: For each element in the set, you can either include it in a subset or exclude it, leading to a
recursive exploration of both possibilities.