CS51A - Spring 2019 - Class 16
Example code in this lecture
mystery_recursion.py
turtle_recursion.py
Lecture notes
the four steps to writing a recursive function:
1. define what the function header is
2. define the recursive case
3. define the base case
4. put it all together
What does mystery_recursion function in
mystery_recursion.py code
do?
- Recursive function
- Work through a small example:
- rec_mystery([2, 4, 3, 1])
rec_mystery([2, 4, 3, 1]) # when recursive call finishes: compares m = 4 and l[0] = 2 and returns 4
|
|
---> rec_myster([4, 3, 1]) # when recursive call finishes: compares m = 3 and l[0] = 4 and returns 4
|
|
-->rec_mystery([3, 1]) # when recursive call finishes: compares m = 1 and l[0] = 3 and returns 4
|
|
--> rec_mystery([1]) # returns 1
- what does this function do?
- calculates the max!
- how?
1. rec_max(list)
2. rec_max(list) = ??? rec_max(list[1:])
- assume/trust that the recursive call works
- if it does, then it will return the largest value in list[1:]
- the largest value of the whole list is then either the first element (l[0]) or the largest value in the rest of the list (rec_max(list[1:])
3. The list will get smaller and smaller. max([]) doesn't really make sense, so our base case will be when there's a single element
- recursive case:
- make a recursive call on the rest of the list
- store that value in m
- compare m to the first element and return whichever it larger
look at the spiral function in
turtle_recursion.py code
- for example, what would the picture look like if I called:
>>> spiral(80, 50)
- what does this function do?
- recursive function
- draws a spiral on the screen
- forward 80
- left 30
- spiral( 76, 49 )
- forward 76
- left 30
- spiral(72.2, 48)
- forward 72.2
- left 30
- ...
- when does it stop?
- when levels == 0
- I put a dot here just do make it explicit
- we could have also just done nothing if we wanted
- repeat 50 times:
- forward length
- left 30
- reduce length by 5%
- what if we wanted to end up back at the starting point, but we couldn't pick the pen up?
- one way would be to trace our steps backward
- Assume that the recursive call returns back to its starting point. What would we need to do to make sure that our call returned back to the starting point?
- Add the following after the recursive call:
right(30)
backward(length)
- if we run it now, we draw the spiral all the way down, and then we retrace backwards
- why does this work?
- each call to spiral retraces its own part after the recursive call
- the stack keeps track of each of the recursive calls
run broccoli_demo function in
turtle_recursion.py code
1. define what the function header is
- broccoli(x, y, length, angle)
2. define the recursive case
- broccoli is a line with three other broccolis at the end
- one directly straight out
- one 20 degrees to the left
- one 20 degrees to the right
- the three other broccolis should be smaller/shorter than the current
3. define the base case
- eventually the length of the broccoli to be drawn gets too short
- at that point instead of recursing, we draw a yellow dot at the end and stop recursing
4. put it all together
- look at broccoli function in
turtle_recursion.py code
- draw a line in the direction specified
- check the base case
- if the line length is less than 10, just put a yellow dot at the end
- otherwise, it's the recursive case
- draw three smaller broccolis at different angles
- what are new_x and new_y?
- the ending coordinates of the line being drawn
- why do we need to save them?
- after the first recursive call to broccoli the turtle won't be in the same place
- if we turn tracing back on, what will we see, that is, what order will it draw in?
- going to go right (angle -20) over and over again until it gets too short
- it will end the recursion then draw a short center
- this also will be a base case and draw the left
- then it will start to work it's way back up
- eventually, it will make it back up to the top-level and start drawing the center stalk
- after drawing the center stalk, it will draw the left stalk
Why does recursion work?
- Specifically, why can we trust that the recursive call is going to work?
- The base case works (assuming we coded it up correctly)
- If the base case works, the the call before the base case works
- If that works, then the call before that works.
- Etc, etc.