Week 11: Recursion

Week 11 Goals

  • Complexity Analysis of Sorting (wrapup)

  • Introduction to Recursion

  • Tracing Recursive Functions

  • Developing Recursive Functions

    • Base Case

    • Recursive Case

    • Combining Recursive result and additional work to get final result

Get Week 11 In-class Code

To copy over the week 11 in-class example programs, do the following (If you have trouble with either of these steps, ask a Ninja or your professor for help):

  1. Create a w11-recursion subdirectory in your cs21/inclass directory, and cd into it:

    $ cd ~/cs21/inclass
    $ mkdir w11-recursion
    $ cd w11-recursion
    $ pwd
    /home/yourusername/cs21/inclass/w11-recursion
  2. Copy over the week 11 files into your w11-recursion subdirectory (check that they copied successfully copied by running ls:

    $ cp ~admin21/public/w11-recursion/*.py ./
    $ ls
    counting.py   palindrome.py  printmessage.py  sorted.py factorial.py  power.py       slicing.py       sum.py

Week 11 Files

  • printmessage.py - print a message n times

  • sum.py - sum integers between 1 and n

  • counting.py - practice tracing recursion

  • power.py - raise a number to a power

  • factorial.py - compute n!, the factorial of n

  • sorted.py - check if a list is sorted

  • palindrome.py - check if a string is a palindrome

  • slicing.py - practice slicing strings

Finishing Sorting

Before moving on to new content, let’s wrap up a few things about sorting from last week.

Recursion

Any function that sometimes calls itself is known as a recursive function. In most cases, recursion can be considered an alternative to iteration (loops). Instead of defining a loop structure, recursion defines a problem as a smaller problem until it reaches an end point. There are three requirements for a successful recursive function:

  1. Base case: each function must have one or more base cases where the function does not make a recursive call to itself. Instead, the problem has reached its smallest point, and we can begin returning back the small solutions.

  2. Recursive case: the function makes one (or more) calls to itself. The call must use a different argument to the function (or else we keep making the same recursive call over and over again!). Typically, the problem gets 1 smaller.

  3. All possible recursive calls must be guaranteed to hit a base case. If you miss one, your program is susceptible to an infinite recursion bug!

Example: Print a Message

The printmessage.py program prints a given message n times. We’ve already seen how to solve this problem with a loop (this is known as an iterative solution, one that uses a loop to repeat). However, let’s explore how we can solve it without a loop using recursion.

To think about how to define printing a message n times in a recursive way, we want to define printing in terms of printing. In other words we want to think of a recursive definition of printing n things, and our recursive function’s structure will follow this with it recursive function calls:

printmessage(msg, num_times) is equivalent to:

  1. print(msg)
  2. printmessage(msg, num_times-1)  # here is our recursive definition

To understand what’s happening with recursion, it’s often helpful to draw a stack diagram. The key concept is that Python treats the recursive function call the same as any other function call — it places a new stack frame on top and begins executing the new function. The only difference is the function in this case has the same name.

Tips for Recursion

For any recursive problem, think of these questions:

  1. What is the base case? In what instances is the problem small enough that we can solve the problem directly? Sometimes you may need more than one base case, but rarely do you need several.

  2. What is the recursive call? Make one or calls in the function to itself. It is very important to use different arguments (usually "smaller") in the recursive call otherwise you obtain infinite recursion.

  3. Do all possible chains of recursion lead to a base case?

  4. If a recursive function is supposed to return a value, make sure all cases return a value and that recursive calls do something with the return value of the smaller problem before returning.