10/14/15

A Mathematical Example: Factorial Example: Fibonnaci Sequence

• Non-recursive definition: • Sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ... a0 a1 a2 a3 a4 a5 a6 n! = n × n-1 × … × 2 × 1 § Get the next number by adding previous two

= n (n-1 × … × 2 × 1) § What is a8? • Recursive definition: • Recursive definition: § a = a + a Recursive Case n! = n (n-1)! for n ≥ 0 Recursive case n n-1 n-2 § a0 = 1 Base Case 0! = 1 Base case § a1 = 1 (another) Base Case

What happens if there is no base case? Why did we need two base cases this time?

Fibonacci as a Recursive Function Fibonacci: # of Frames vs. # of Calls def fibonacci(n): • Function that calls itself • Fibonacci is very inefficient. """Returns: Fibonacci no. an § Each call is new frame § fib(n) has a stack that is always ≤ n Precondition: n ≥ 0 an int""" § Frames require memory § But fib(n) makes a lot of redundant calls if n <= 1: § ∞ calls = ∞ memo ry return 1 fib(5) fibonacci 3 Path to end = fib(4) fib(3) return (fibonacci(n-1)+ n 5 the call stack fibonacci(n-2)) fib(3) fib(2) fib(2) fib(1)

fibonacci 1 fibonacci 1 fib(2) fib(1) fib(1) fib(0) fib(1) fib(0) n 4 n 3

fib(1) fib(0)

How to Think About Recursive Functions Understanding the String Example

1. Have a precise function specification. def num_es(s): • Break problem into parts """Returns: # of 'e's in s""" 2. Base case(s): # s is empty number of e’s in s = § When the parameter values are as small as possible if s == '': Base case number of e’s in s[0] § When the answer is determined with little calculation. return 0 + number of e’s in s[1:] 3. Recursive case(s): # s has at least one 'e' • Solve small part directly § Recursive calls are used. if s[0] == 'e': Recursive case return 1+num_es(s[1:]) § Verify recursive cases with the specification number of e’s in s = 4. Termination: return num_es(s[1:])) number of e’s in s[1:] § Arguments of calls must somehow get “smaller” (+1 if s[0] is an 'e') 0 1 len(s) (+0 is s[0] not an 'e') § Each recursive call must get closer to a base case s H ello World!

1 10/14/15

Understanding the String Example Understanding the String Example

• Step 1: Have a precise specification • Step 3: Recursive calls make progress toward termination def num_es(s): def num_es(s): parameter s """Returns: # of 'e's in s""" “Write” your return """Returns: # of 'e's in s""" argument s[1:] is smaller than # s is empty statement using the # s is empty parameter s, so there is progress if s == '': Base case specification if s == '': toward reaching base case 0 return 0 return 0 # return # of 'e's in s[0]+# of 'e's in s[1:] # return # of 'e's in s[0]+# of 'e's in s[1:] if s[0] == 'e': if s[0] == 'e': return 1+num_es(s[1:]) return 1+num_es(s[1:]) argument s[1:] Recursive case return num_es(s[1:])) return num_es(s[1:])) • Step 2: Check the base case • Step 4: Check the recursive case § When s is the empty string, 0 is (correctly) returned. § Does it match the specification?

Exercise: Remove Blanks from a String Exercise: Remove Blanks from a String

1. Have a precise specification def deblank(s): • Sometimes easier to break """Returns: s with blanks removed""" def deblank(s): up the recursive case if s == '': """Returns: s but with its blanks removed""" § Particularly on small part return s § Write recursive case as a 2. Base Case: the smallest String s is ''. sequence of if-statements # s is not empty • Write code in pseudocode if s == '': if s[0] is a blank: § return s return s[ 1:] with blanks removed Mixture of English and code § Similar to top-down design 3. Other Cases: String s has at least 1 character. # s not empty and s[0] not blank • Stuff in red looks like the return (s[0] with blanks removed) + (s[1:] with blanks removed) return (s[0] + function specification! s[ 1:] with blanks removed) § But on a smaller string § Replace with deblank(s[1:])

Example: Reversing a String Example: Reversing a String

• Precise Specification: def reverse(s): H e l l o ! H e l l o ! § Returns: reverse of s """Returns: reverse of s • Solving with recursion Precondition: s a string""" § Suppose we can reverse # s is empty a smaller string ! o l l e H if s == '': ! o l l e (e.g. less one character) return s § Can we use that solution ✔ 1. Precise specification? H e l l o ! to reverse whole string? # s has at least one char ✔ 2. Base case: correct? # (reverse of s[1:])+s[0] ✔ 3. Recursive case: • Often easy to understand return reverse(s[1:])+s[0] progress to termination? first without Python ✔ 4. Recursive case: correct? § Then sit down and code ! o l l e

2