CS 051 Fall 2011

Lecture 17

Recursive Data Structures

Recursion can be a very powerful tool in programming. The basic idea is that something is
defined in terms of smaller items or values of the same type.

If we consider a drawing of a target, we might view it is a collection of concentric rings,
with a bull's eye at the center. We could imagine writing a program to draw such an object
using a while loop.

There is another way. We could define a Target recursively. For example, we could define a
Target to be an outer ring combined with a smaller Target inside. If we do this, then the
smaller Target inside would be defined as its outer ring, combined with an even smaller
Target. In order to stop this process so that it doesn't continue forever, we can decide that
if the smaller inside Target is below a certain size, we will just draw a bull's eye, and
stop creating smaller Targets.

In this example, creating a Target from an outer ring and a smaller Target is called our
recursive case. Just drawing the bull's eye is called our base case.

Our class example BullsEyeController shows what this defnition would look like in Java code.

We follow four basic steps when we think about recursion:

  1. Define an interface with all of the methods that both base case and recursive case
    classes must implement.
  2. Define one or more classes representing base cases. Make sure that all methods from
    the interface are implemented. Convince yourself that the constructors and methods work correctly.
  3. Define the constructors for recursive classes. Recursive calls of the constructor
    should only create objects that are simpler than the one being built by the constructor.
    Similarly, instance variables whose types are either the interface or class should only
    refer to objects simpler than the one being constructed. In particular, the construction
    of simpler objects in the constructor body should eventually end up at a base case.
    Convince yourself that the constructor will be correct under the assumption that the
    construction of simpler objects is correct.
  4. Write each method under the assumption that it works correctly on all simpler objects.
    Convince yourself that the methods will be correct under the assumption that instance
    variables hold simpler objects.

We also looked at writing a recursive version of our Scribbler program from earlier in the
semester. This program looked very similar to our bull's eye program, with a couple of
interesting differences.

The Scribbler recursive class constructor does not actually
recursively call itself. The recursive class does, however, declare an instance variable
of the same type that it is implemented by the class, which indicates recursion.

Also, the Scribbler program uses an empty base case. The base case does not necessarily need
to contain an object, but it needs to represent a simpler object of the same type. In this
example, and empty scribble is still a scribble. The class example SimpleRecScribbler