CS51A - Spring 2019 - Class 15

Example code in this lecture

   recursion.py

Lecture notes

  • administrative
       - Thursday office hours: 2-3pm

  • 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

  • write a recursive function called rec_sum_list 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_list(some_list) = some_list[0] + rec_sum_list(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_list function in recursion.py code
          - check the base case first
             - if the list is empty
             - we could have also done if len(some_list) == 0
          - otherwise
             - do exactly our recursive relationship

       - Why does this work?!?
          - Let's look at an example:

          rec_sum_list([1, 2, 3, 4])
             |
             V
             1 + rec_sum_list([2,3,4])
                |
                V
                2 + rec_sum_list([3, 4])
                   |
                   V
                   3 + rec_sum_list([4])
                      |
                      V
                      rec_sum_list([])

           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 (see rec_sum_list_print in recursion.py code):
          - If we run this with [1, 2, 3, 4] we get:

             rec_sum_list([1, 2, 3, 4])
             Calling rec_sum_list: [1, 2, 3, 4]
             Calling rec_sum_list: [2, 3, 4]
             Calling rec_sum_list: [3, 4]
             Calling rec_sum_list: [4]
             Calling rec_sum_list: []
             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

  • write a function called power that takes a base and an exponent and returns base^exponent (i.e. the same thing as '**' without using '**')
       - you can assume that exponent >= 0

       1. define what the function header is
          def power(base, exponent)

       2. define the recursive case
          b^e = b * b^(e-1)

          - we can define the power function as the power function of the exponent - 1 times the base

       3. define the base case
          - each time the exponent is getting smaller
          - eventually, the exponent will be 0
             - b^0 = 1

       4. look at the power function in recursion.py code
          - check the base case when the exponent == 0
             - in this case just return 1
          - otherwise, do the recursive case
             - base * power(base, exponent-1)