#!/usr/bin/env python # coding: utf-8 # ## Recursion # This function prints the given `text` the given `numberOfTimes`. # # ```python # def repeatPrint(text, numberOfTimes): # # Write solution here... # ``` # # For example: # # ```python # repeatPrint('Hello!', 3) # ``` # # Should output: # # ``` # Hello! # Hello! # Hello! # ``` # In[31]: # Implementation of repeatPrint using a for loop: def repeatPrint(text, numberOfTimes): for i in range(numberOfTimes): print(text) # Let's try it: repeatPrint('Hello!', 3) # In[32]: # Implementation of repeatPrint using a while loop: def repeatPrint(text, numberOfTimes): i = 0 while i < numberOfTimes: print(text) i += 1 # Let's try it: repeatPrint('Hello!', 3) # Let us now define `repeatPrint` using a technique called **Recursion**. A _recursive function_ is a function that calls itself. # In[33]: # Implementation of repeatPrint using recursion: def repeatPrint(text, numberOfTimes): if numberOfTimes == 0: # If the number of times to print is 0, there is no work to do. return # Print the text once. print(text) # Now we have one fewer number of times to print the text. numberOfTimesRemaining = numberOfTimes - 1 repeatPrint(text, numberOfTimesRemaining) # Let's try it: repeatPrint('Hello!', 3) # Every recursive function has two important parts: the **base case** and the **recursive case**. # # The **base case** occurs when we have the simplest possible input to the function, where the answer is obvious. For `repeatPrint` the base case occurs when `numberOfTimes == 0`. # # The **recursive case** occurs all other times from the **base case** where we are required to call the function itself with a different input (that gets one step closer to the base case). For `repeatPrint` the recursive case occurs when `numberOfTimes > 0`. # In[ ]: # What happens if we forget the base case? def repeatPrint(text, numberOfTimes): # Print the text once. print(text) # Now we have one fewer number of times to print the text. numberOfTimesRemaining = numberOfTimes - 1 repeatPrint(text, numberOfTimesRemaining) # Let's try it: repeatPrint('Hello!', 3) # Answer: repeatPrint will recursively call itself repeatedly, without stopping! # So this bad code. Similar to an infinite loop. # Let us try out recursion with another example. # # The following sequence is called the **Fibonacci sequence**: # # ``` # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ... # ``` # # Can you see the pattern in this sequence? # # The **Fibonacci sequnce** is defined as follows: # # ``` # F(0) = 0 # F(1) = 1 # F(n) = F(n - 1) + F(n - 2), for n >= 2 # ``` # # We can expand this out a bit to see the first few elements of this sequence: # # ``` # F(0) = 0, by definition # F(1) = 1, by definition # F(2) = F(1) + F(0) = 1 + 0 = 1 # F(3) = F(2) + F(1) = 1 + 1 = 2 # F(4) = F(3) + F(2) = 2 + 1 = 3 # F(5) = F(4) + F(3) = 3 + 2 = 5 # ... # ``` # # This sequence appears in algorithms, math, and in nature in various places. We will not discuss the sequence itself in detail, but you can read more about it here: https://en.wikipedia.org/wiki/Fibonacci_number. # Let us define a function ```fib(n)``` that computes the $n^{th}$ Fibonacci number. # # ```python # def fib(n): # # Write solution here... # ``` # In[34]: # Implementation of fib using for loop: def fib(n): if n == 0 or n == 1: return n fib_i_prev_prev = 0 # Initialized to F(0) fib_i_prev = 1 # Initialized to F(1) for i in range(n - 1): # Compute the next number in the sequence fib_i = fib_i_prev_prev + fib_i_prev # Save state to use for the next computation fib_i_prev_prev = fib_i_prev fib_i_prev = fib_i return fib_i # Let's try it: fib(4) # In[35]: # Implementation of fib using recursion: def fib(n): # Base case: if n == 0 or n == 1: return n # Recursive case: return fib(n - 1) + fib(n - 2) # Let's try it: fib(4) # Let us practice how to understand recursive functions with a couple more examples. # In[36]: # What is the behavior of this function? def mystery(a): if a == 0: return 0 return a + mystery(a - 1) mystery(4) # Answer: # mystery(a) = 0 + 1 + 2 + ... + a # In[37]: # What is the behavior of this functioin? def mystery2(a, b): if b == 0: return 0 return a + mystery2(a, b - 1) mystery2(5, 4) # Answer: # mystery2(a, b) = a * b