Lecture 16 - Recursive Data Structures

Let's next look at the case of building interesting pictures using recursion. Our first project will be to draw targets. We will look at this process recursively. A target consists of an outer ring with a slightly smaller target inside. When it gets small enough, the target consists of just the outer ring. However, because we need to have a value for the inner target we define something called an emptyTarget. It has type Target, but doesn't actually drawn anything. See the definitions in TargetApp.

While you could probably figure out how to draw a target with a while loop, you do not yet know how to keep track of all of the pieces so they can be dragged around. (Later we will see how to do this with arrays.)

Instead our solution involved defining a type (Target), the trivial object emptyTarget, and a class that implements more complex targets: RingedTarget. RingedTarget represents a recursive data structure because it has an instance variable referring to the same type of object as the class implements.

We talked in class about how to think about recursion:

  1. Define an type with all of the methods that both base case and recursive case classes must implement.
  2. Define an object or class representing the base case(s). Make sure that all methods from the type are implemented. Convince yourself that the methods work correctly. (Usually they just do very trivial things!)
  3. Define the recursive class(es). Defs and instance variables that have the same type of object as being constructed should only refer to objects simpler than the one being constructed. In particular, the construction of simpler objects in the body of the class should eventually end up at a base case. Convince yourself that the initialization 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.

See the definitions in Scribble and SincleScribbler for a program that not only allows you to draw scribbles, but also let you move them, color them, and erase them. This also uses a recursive data structure, built from a base class of emptyScribble and a recursive case of scribble.

Notice that selecting a color allows the user to change the color of the last scribble drawn. Clicking the erase button erases the last scribble drawn. However, if you click it again, nothing will happen. Notice how emptyScribble is used in SingleScribbler to make sure that currentScribble always has a value.