|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "id": "83b2b8de", |
| 6 | + "metadata": {}, |
| 7 | + "source": [ |
| 8 | + "# Recursion\n", |
| 9 | + "\n", |
| 10 | + "Recursion in Python is a programming technique where a function calls itself within its own definition. This approach is used to solve problems that can be broken down into smaller, self-similar subproblems. \n", |
| 11 | + "\n", |
| 12 | + "Key Concepts:\n", |
| 13 | + "Base Case:\n", |
| 14 | + "A condition that stops the recursion. Without a base case, the function would call itself infinitely, leading to a stack overflow error.\n", |
| 15 | + "Recursive Case:\n", |
| 16 | + "The part of the function where it calls itself with a modified input, working towards the base case.\n", |
| 17 | + "How it Works:\n", |
| 18 | + "A recursive function is called with an initial input.\n", |
| 19 | + "The function checks for the base case. If the base case is met, it returns a value, stopping the recursion.\n", |
| 20 | + "If the base case is not met, the function executes the recursive case, calling itself with a modified input.\n", |
| 21 | + "This process continues until the base case is reached, and the results of each recursive call are combined to produce the final output." |
| 22 | + ] |
| 23 | + }, |
| 24 | + { |
| 25 | + "cell_type": "code", |
| 26 | + "execution_count": null, |
| 27 | + "id": "243d91de", |
| 28 | + "metadata": {}, |
| 29 | + "outputs": [], |
| 30 | + "source": [ |
| 31 | + "def factorial(n):\n", |
| 32 | + " if n == 0: # Base case: factorial of 0 is 1\n", |
| 33 | + " return 1\n", |
| 34 | + " else: # Recursive case: n! = n * (n-1)!\n", |
| 35 | + " return n * factorial(n-1)\n", |
| 36 | + "\n", |
| 37 | + "print(factorial(5)) # Output: 120" |
| 38 | + ] |
| 39 | + }, |
| 40 | + { |
| 41 | + "cell_type": "markdown", |
| 42 | + "id": "66c502ca", |
| 43 | + "metadata": {}, |
| 44 | + "source": [ |
| 45 | + "Types of Recursion:\n", |
| 46 | + " \n", |
| 47 | + "Direct Recursion: A function directly calls itself.\n", |
| 48 | + "Indirect Recursion: A function calls another function, which in turn calls the first function. \n", |
| 49 | + " \n", |
| 50 | + "Advantages:\n", |
| 51 | + "Can provide elegant and concise solutions for certain problems.\n", |
| 52 | + "Can simplify complex algorithms by breaking them into smaller subproblems.\n", |
| 53 | + "\n", |
| 54 | + "Disadvantages:\n", |
| 55 | + "Can be less efficient than iterative solutions due to function call overhead.\n", |
| 56 | + "Can lead to stack overflow errors if the recursion depth is too large.\n", |
| 57 | + "May be harder to understand and debug compared to iterative approaches.\n", |
| 58 | + "\n", |
| 59 | + "Use Cases:\n", |
| 60 | + "Tree traversals (e.g., depth-first search).\n", |
| 61 | + "Mathematical problems (e.g., factorial, Fibonacci sequence).\n", |
| 62 | + "Parsing hierarchical data structures (e.g., XML, JSON).\n", |
| 63 | + "Divide-and-conquer algorithms (e.g., quicksort, mergesort)." |
| 64 | + ] |
| 65 | + }, |
| 66 | + { |
| 67 | + "cell_type": "markdown", |
| 68 | + "id": "a1db9ee3", |
| 69 | + "metadata": {}, |
| 70 | + "source": [ |
| 71 | + "Recursion involves a function calling itself directly or indirectly to solve a problem by breaking it down into simpler and more manageable parts. In Python, recursion is widely used for tasks that can be divided into identical subtasks.\n", |
| 72 | + "\n", |
| 73 | + "In Python, a recursive function is defined like any other function, but it includes a call to itself. The syntax and structure of a recursive function follow the typical function definition in Python, with the addition of one or more conditions that lead to the function calling itself." |
| 74 | + ] |
| 75 | + }, |
| 76 | + { |
| 77 | + "cell_type": "code", |
| 78 | + "execution_count": null, |
| 79 | + "id": "8806d749", |
| 80 | + "metadata": {}, |
| 81 | + "outputs": [], |
| 82 | + "source": [ |
| 83 | + "def factorial(n):\n", |
| 84 | + " if n == 0:\n", |
| 85 | + " return 1\n", |
| 86 | + " else:\n", |
| 87 | + " return n * factorial(n-1)\n", |
| 88 | + "\n", |
| 89 | + "print(factorial(5))" |
| 90 | + ] |
| 91 | + }, |
| 92 | + { |
| 93 | + "cell_type": "markdown", |
| 94 | + "id": "f2a9ef37", |
| 95 | + "metadata": {}, |
| 96 | + "source": [ |
| 97 | + "Explanation: The factorial of a number n (denoted as n!) is the product of all positive integers less than or equal to n. The recursive approach involves the function calling itself with a decremented value of n until it reaches the base case of 1.\n", |
| 98 | + "\n", |
| 99 | + "Let's understand recursion in python deeply:" |
| 100 | + ] |
| 101 | + }, |
| 102 | + { |
| 103 | + "cell_type": "code", |
| 104 | + "execution_count": null, |
| 105 | + "id": "65163d30", |
| 106 | + "metadata": {}, |
| 107 | + "outputs": [], |
| 108 | + "source": [ |
| 109 | + "def recursive_function(parameters):\n", |
| 110 | + "\n", |
| 111 | + " if base_case_condition:\n", |
| 112 | + "\n", |
| 113 | + " return base_result\n", |
| 114 | + "\n", |
| 115 | + " else:\n", |
| 116 | + "\n", |
| 117 | + " return recursive_function(modified_parameters)" |
| 118 | + ] |
| 119 | + }, |
| 120 | + { |
| 121 | + "cell_type": "markdown", |
| 122 | + "id": "23bb548a", |
| 123 | + "metadata": {}, |
| 124 | + "source": [ |
| 125 | + "Base Case and Recursive Case\n", |
| 126 | + "Base Case: This is the condition under which the recursion stops. It is crucial to prevent infinite loops and to ensure that each recursive call reduces the problem in some manner. In the factorial example, the base case is n == 1.\n", |
| 127 | + "Recursive Case: This is the part of the function that includes the call to itself. It must eventually lead to the base case. In the factorial example, the recursive case is return n * factorial(n-1)." |
| 128 | + ] |
| 129 | + }, |
| 130 | + { |
| 131 | + "cell_type": "code", |
| 132 | + "execution_count": null, |
| 133 | + "id": "0f6d02bd", |
| 134 | + "metadata": {}, |
| 135 | + "outputs": [], |
| 136 | + "source": [ |
| 137 | + "def fibonacci(n):\n", |
| 138 | + " if n == 0:\n", |
| 139 | + " return 0\n", |
| 140 | + " elif n == 1:\n", |
| 141 | + " return 1\n", |
| 142 | + " else:\n", |
| 143 | + " return fibonacci(n-1) + fibonacci(n-2)\n", |
| 144 | + "\n", |
| 145 | + "print(fibonacci(10))" |
| 146 | + ] |
| 147 | + }, |
| 148 | + { |
| 149 | + "cell_type": "markdown", |
| 150 | + "id": "64d4ce84", |
| 151 | + "metadata": {}, |
| 152 | + "source": [ |
| 153 | + "Explanation:\n", |
| 154 | + "\n", |
| 155 | + "Base Cases: If n == 0, the function returns 0. If n == 1, the function returns 1. These two cases are necessary to stop the recursion.\n", |
| 156 | + "Recursive Case: The function calls itself twice with the decrements of n (i.e., fibonacci(n-1) and fibonacci(n-2)), summing the results of these calls. This division into smaller subproblems continues until the base cases are reached." |
| 157 | + ] |
| 158 | + }, |
| 159 | + { |
| 160 | + "cell_type": "markdown", |
| 161 | + "id": "b8dc2e8b", |
| 162 | + "metadata": {}, |
| 163 | + "source": [ |
| 164 | + "Recursion vs Iteration\n", |
| 165 | + "\n", |
| 166 | + "Recursion:\n", |
| 167 | + "Recursion is often more intuitive and easier to implement when the problem is naturally recursive, like tree traversals.\n", |
| 168 | + "It can lead to solutions that are easier to understand compared to iterative ones.\n", |
| 169 | + "\n", |
| 170 | + "Iteration:\n", |
| 171 | + "Iteration involves loops (for, while) to repeat the execution of a block of code.\n", |
| 172 | + "It is generally more memory-efficient as it does not involve multiple stack frames like recursion.\n", |
| 173 | + "\n", |
| 174 | + "Advantages of using recursion\n", |
| 175 | + "Simplicity: Recursive code is generally simpler and cleaner, especially for problems inherently recursive in nature (e.g., tree traversals, dynamic programming problems).\n", |
| 176 | + "Reduced Code Length: Recursion can reduce the length of the code since the repetitive tasks are handled through repeated function calls.\n", |
| 177 | + "Disadvantages of using recursion\n", |
| 178 | + "Memory Overhead: Each recursive call adds a new layer to the stack, which can result in significant memory use, especially for deep recursion.\n", |
| 179 | + "Performance Issues: Recursive functions may lead to slower responses due to overheads like function calls and returns.\n", |
| 180 | + "Risk of Stack Overflow: Excessive recursion can lead to a stack overflow error if the recursion depth exceeds the stack limit." |
| 181 | + ] |
| 182 | + } |
| 183 | + ], |
| 184 | + "metadata": { |
| 185 | + "kernelspec": { |
| 186 | + "display_name": "Python 3 (ipykernel)", |
| 187 | + "language": "python", |
| 188 | + "name": "python3" |
| 189 | + }, |
| 190 | + "language_info": { |
| 191 | + "codemirror_mode": { |
| 192 | + "name": "ipython", |
| 193 | + "version": 3 |
| 194 | + }, |
| 195 | + "file_extension": ".py", |
| 196 | + "mimetype": "text/x-python", |
| 197 | + "name": "python", |
| 198 | + "nbconvert_exporter": "python", |
| 199 | + "pygments_lexer": "ipython3", |
| 200 | + "version": "3.9.12" |
| 201 | + } |
| 202 | + }, |
| 203 | + "nbformat": 4, |
| 204 | + "nbformat_minor": 5 |
| 205 | +} |
0 commit comments