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:
- Define an interface with all of the methods that both base case and recursive case
classes must implement.
- 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.
- 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.
- 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.