CS30  Spring 2016  Class 9
Example code in this lecture
recursion.py
Lecture notes
administrative
 assignment 4 out
 slightly later due date (Friday at 6pm)
 can be challenging, so start soon!
 midterm next Tuesday
 I'll talk more about this soon, but wanted it on your radar
"in"
the call stack
 what is displayed if we call mystery(2, 3), given the following functions?
def a():
return 10
def b(num):
return num + a()
def c(num1, num2):
return b(num1 * num2)  1
def mystery(num1, num2):
print "The mystery number is: " + str(c(num1, num2))
 The mystery number is: 15
 why?
 We can visualize each of these function calls:
mystery(2, 3)

V
"The mystery number is: " + c(2, 3)

V
b(6)  1

V
6 + a()

V
10
 Finally, when a returns it's value then we can work our way back and get the final answer
 a() returns 10
 which allows b to now return 16
 once c knows it's call to b was 16, it returns 15
 and finally, we can generate the string that the mystery function prints out
 the way that the computer keeps track of all of this is called the "stack"
 as functions are called, the stack grows
 new function calls are added onto the stack
 when functions finished, the stack shrinks
 that function call is removed
 its result is given to the next function on the stack (the function that called it)
 you can actually see this stack (called the "call stack"), when you get an error, e.g. we change a to "return 10 + ''":
 when we run it we see:
mystery(2, 3)
Traceback (most recent call last):
Python Shell, prompt 2, line 1
File "/Users/drk04747/classes/cs30/lectures/lecture9recursion/example/example.py", line 11, in <module>
print "The mystery number is: " + str(c(num1, num2))
File "/Users/drk04747/classes/cs30/lectures/lecture9recursion/example/example.py", line 8, in <module>
return b(num1 * num2)  1
File "/Users/drk04747/classes/cs30/lectures/lecture9recursion/example/example.py", line 5, in <module>
return num + a()
File "/Users/drk04747/classes/cs30/lectures/lecture9recursion/example/example.py", line 2, in <module>
return "" + 10
TypeError: cannot concatenate 'str' and 'int' objects
 it's a little bit cryptic, but if you look on the right, you see the call from mystery, to c, to b and finally to a
write a function called factorial that takes a single parameter and returns the factorial of that number
>>> factorial(1)
1
>>> factorial(2)
2
>>> factorial(3)
6
>>> factorial(8)
40320
 look at factorial_iterative function in recursion.py
 I'm guessing most people wrote it this way
 does a loop from 1 up to n and multiplies the numbers
 could we have done it any other way?
recursion
 a recursive function is defined with respect to itself
 what does this mean?
 somewhere inside the function, the function calls itself
 just like any other function call
 the recursive call should be on a "smaller" version of the problem
 can we write factorial recursively?
 key idea: try and break down the problem into some computation, plus a smaller subproblem that looks similar
5! = 5 * 4 * 3 * 2 * 1
5! = 5 * 4!
 a first try:
def factorial(n):
return n * factorial(n1)
 what happens if we run this with say 5?
5 * factorial(4)

V
4 * factorial(3)

V
3 * factorial(2)

V
2 * factorial(1)

V
1 * factorial(0)

V
0 * factorial(1)
...
 at some point we need to stop. this is called the "base case" for recursion
 when is that?
 when n = 1 (or if you want to account for 0!, at 0)
 how can we change our function to do this?
 look at factorial function in
recursion.py code
 first thing, check to see if we're at the base case (if n == 0)
 if so, just return 1 (this lets 0! be 1)
 otherwise, we fall into our recursive case:
 n * factorial(n1)
writing recursive functions
1. define what the function header is
 what is the name of the function?
 what parameters does the function take?
2. define the recursive case
 pretend you had a working version of your function, but it only works on smaller versions of your current problem, how could you write your function?
 the recursive problem should be getting "smaller", by some definition of smaller, e.g
 for smaller numbers (like in factorial)
 for lists that are smaller/shorter
 for strings that are shorter
 other ideas:
 sometimes define it in English first and then translate that into code
 often nice to think about it mathematically, using equals
3. define the base case
 recursive calls should be making the problem "smaller"
 what is the smallest (or simplest) problem? This is often the base case
4. put it all together
 first, check the base case
 return something (or do something) for the base case
 if the base case isn't true
 calculate the problem using the recursive definition
 return the answer
 recursion has a similar feel to "induction" in mathematics
 proof by induction in mathematics:
1. show something works the first time (base case)
2. assume that it works for some time
3. show it will work for the next time (i.e. time after "some time")
4. therefore, it must work for all the times
write a recursive function called rec_sum that takes a list of numbers as a parameter and calculates their sum
1. define what the function header is
def sum(some_list)
2. define the recursive case
 pretend like we have a function called sum that we can use but only on smaller strings
 what would we get back if we called sum on everything except the first element?
 the sum of all of those elements
 how would we get the sum to the entire list?
 just add that element to the sum of the rest of the elements
 the recursive relationship is:
rec_sum(some_list) = some_list[0] + rec_sum(some_list[1:])
3. define the base case
 in each case the list is going to get shorter
 eventually, it will be an empty list. what is the sum of an empty list?
 0
4. put it all together!  look at the rec_sum function in
recursion.py code
 check the base case first
 if the list has length 0, return 0
 we could have also done if some_list == []:
 otherwise
 do exactly our recursive relationship
 Why does this work?!?
 Let's look at an example:
rec_sum([1, 2, 3, 4])

V
1 + rec_sum([2,3,4])

V
2 + rec_sum([3, 4])

V
3 + rec_sum([4])

V
rec_sum([])
finally we hit the base case and we get our answer to rec_sum([]), which is 0, and then rec_sum([4]) can return its answer, etc.
 We can actually see this happening by adding some print statements to our function:
def rec_sum(some_list):
print "Calling rec_sum: " + str(some_list)
if len(some_list) == 0:
print "base case returning 0"
return 0
else:
temp = some_list[0] + rec_sum(some_list[1:])
print str(some_list) + " returning " + str(temp)
return temp
 If we run this with [1, 2, 3, 4] we get:
rec_sum([1, 2, 3, 4])
Calling rec_sum: [1, 2, 3, 4]
Calling rec_sum: [2, 3, 4]
Calling rec_sum: [3, 4]
Calling rec_sum: [4]
Calling rec_sum: []
base case returning 0
[4] returning 4
[3, 4] returning 7
[2, 3, 4] returning 9
[1, 2, 3, 4] returning 10
10
 like the diagram above, we see all the calls down to the recursive calls
 then, the base case returns 0
 then each of the successive calls slowly returns their answer
write a recursive function called reverse that takes a string as a parameter and reverses the string
1. define what the function header is
def reverse(some_string)
2. define the recursive case
 pretend like we have a function called reverse that we can use but only on smaller strings
 to reverse a string
 remove the first character
 reverse the remaining characters
 put that first character at the end
reverse(some_string) = reverse(some_string[1:]) + some_string[0]
3. define the base case
 in each case the string is going to get shorter
 eventually, it will be an empty string. what is the reverse of the empty string?
 ""
4. look at reverse function in
recursion.py code
 check the base case first: if the length of the string is 0
 otherwise
 call reverse again on the shorter version of the string
 append on what is returned by some_string
 if we added a print statement to reverse to print out each call to reverse what would we see?
 e.g. print "Reverse: " + some_string
>>> reverse("abcd")
Reverse: abcd
Reverse: bcd
Reverse: cd
Reverse: d
Reverse:
 we can also change the function to see what is being returned each time:
>>> reverse("abcd")
Reverse: abcd
Reverse: bcd
Reverse: cd
Reverse: d
Reverse:
Returning:
Returning: d
Returning: dc
Returning: dcb
Returning: dcba
 to reverse the string "abcd", reverse is called four times recursively