CS 101 (Spring 1999)
Lab 9: Multiple Representations

Lab Assigned Design Due
(Mondays 2 PM)
Lab Due
(Fridays 2 PM)
2 Apr 5 Apr 9 Apr


Overview:

You have seen how multple representations can affect performance with respect to a Set. In this lab, you will experiment with multiple representations for a mapping.

Goals:

By the end of this lab, you should This lab contains two parts, design and implementation, due on the dates shown above by 2 PM.

The design will be discussed Monday in class. In Lab, your graded design will be returned. No other handouts or code will be issued. So, think carefully about your design!


Before starting:

[[[ Download PC zip ]]]

Zip includes:

Remember to type the following lines at the top of any files that use the terminal or canvas classes.

import cs101.terminal.*;
import cs101.canvas.*;

Particulars

In this lab, you will implement a "mapping" abstract data type three different ways. All of the implementations will provide the same functionality (same interface) but may differ in their efficiency.

You should think of a "mapping" ADT as a relation between a domain and a range. For example, a telephone directory is a mapping from names to telephone numbers. The domain is all possible names, and the range is all possible phone numbers. Each entry in the mapping is a pair of elements, one from the domain and one from the range. Usually, the domain and range are different, but that is not a requirement.

In this lab, your mapping will be from item names (represented as String objects) to Objects (which can represent any reference type).

Implementation note: To compare String values, you will need to use the provided compareTo method of the String class. The compareTo method takes as its parameter another String, and returns an integer whose value is:

Comparisons are based on lexicographic ordering (dictionary ordering) of strings.

WARNING: Do not use the == operator to compare String values. When == is used on objects, it evaluates to true if both sides of the comparison refer to the same exact memory location (i.e., it's the exact same object). Therefore, even if two String objects contain the same text, the == test for equality on the two objects would return false because they are not the same object.


Three implementations of the Mapping interface

  1. Open the provided file Mapping.java and study the provided code in that file. Notice that the file contains an abstract class that declares the methods that a Mapping should provide. Because it is abstract, the Mapping class cannot be instantiated.

  2. Now open the provided file Startup.java and look at the test procedure. Notice that the parameter to this procedure has type Mapping. This means that this procedure accepts a parameter of type Mapping or any of its subclasses. In this program, three different types of objects will be created and passed to the test procedure. All three are instantiations of different classes, but each extends (directly or indirectly) the Mapping interface. Therefore, Java's support for abstract classes provides the power to define the interface of an ADT and write programs in terms of that interface. Then, you can implement the ADT in different ways and use them in the program, provided that you conform to the defined superclass's definition.

  3. Study again the method declarations in the file Mapping.java, paying attention to the documentation for each method.

  4. You will need a class StringObjPair that can store a pair, consisting of a String (the domain) and an Object (the range). You may choose to pattern this class after the DomainRange class (which contains Domain and Range) in the notes. Or you might think about extending these classes to obtain StringObjPair.

  5. Complete the implementation of UnorderedMapping. You will have to create a new file and add it to your project. Your implementation will probably be similar to the Relation class seen in lecture. For your internal representation, use an unordered list of StringObjPairs. For the unordered list, you may choose to subclass the List.java class seen in lecture.

    In the file Startup.java, create an instance of an UnorderedMapping, and pass it to the test procedure. Verify that the output is correct. Notice that the test procedure just knows it's getting a Mapping. It doesn't care whether it's an UnorderedMapping, or any other kind of Mapping, so long as the class extends the Mapping class.

  6. Complete the implementation of OrderedMapping.java. One of your representation invariants should be that the list is kept in sorted order, according to the values of the String in each pair. Make use of this invariant to improve the efficiency of the map and lookup methods.

    In the file Startup.java, create an instance of an OrderedMapping, and pass it to the test procedure. Again, notice that the test procedure only cares that the object's type implements the mapping interface. Verify that the output is correct. Look at the printed values of the mapping to be sure that your list is being kept in sorted order.

  7. Complete your implementation of ArrayMapping.java. For your internal representation, create an array of references to StringObjPair objects.

    Create the array to allow enough space for 100 pairs. One of your representation invariants should be that the array is kept in sorted order according to the values of the String in each pair. By maintaining this invariant, you can use binary search on the array as discussed in class to improve the efficiency of the lookup method. Note that when you insert an item that belongs somewhere in the middle of the array, you'll have to bump all the items after it down by one to make room for it in the array.

    In the file Startup.java, create an instance of an ArrayMapping, and pass it to the test procedure. Again, notice that the test procedure only cares that the object's type implements the mapping interface. Verify that the output is correct. Look at the printed values of the mapping to be sure that your array is being kept in sorted order.


What to turn in:

Design (due Monday)
  1. Complete a design cover sheet.
  2. Describe the class hierarchy for the classes Mapping, UnorderedMapping, OrderedMapping, and ArrayMapping. You may find it helpful to review the class notes on Set, ListBasedSet, and extensions of ListBasedSet.

    Explain why you subclass where you do. State which methods are inherited without change and which are redefined in the subclasses.

    Think about a representation-specific locate method. For example, the list-based mappings might use locate to return the list element that contains a desired StringObject pair. The array-based mapping might require a different locate, because the internal representation is different.

    Strive to make lookup as general as possible (i.e., as high up in the hierarchy asyou can), possibly by making it use a subclass's locate method.

  3. Describe how you will implement StringObjPair and give the API for that class.
Implementation (due Friday)
  1. Complete a code cover sheet.
  2. Provide a transcript from your self-tests.
  3. Provide a printout of any files you have modified.
  4. Be prepared to demo in lab.


Extra Credit: Binary Search Tree Implementation (due by 23 April 1999 -- must be demo'ed the last week of class)

Before working on this portion of the lab you may want to review the on-line lecture highlights about representing sets as trees.

Implementation the class TreeMapping as a concrete extension of Mapping. For your internal representation, use a binary search tree of StringObjParis. Additionally, each node in the tree will have a (possibly null) left subtree and a (possibly null) right subtree. Your implementation should satisfy the representation invariant that all strings in the left subtree of a given node have values that are less than the string in the node itself. Make use of this invariant to improve the efficiency of the map and lookup method.

The toString method is tricky. Create a string that is a readable representation of the tree. Display the tree sideways, with the root of the tree at the left edge of the page. Your return String should have one node per line, something like this:

                        (quack,4)
            (oink,5)
                        (moo,7)
(meow,2)
                        ()
            (bow wow,8)
                        (baa,5)
This is called an in-order traversal of the tree, since one subtree is traversed first, then the node itself, and then the other subtree. You can use the special character '\n' in a String to cause the terminal to advance to a new line as it prints the string. Hint: The depth of the node in the tree determines how much to indent. So, use a helper procedure with a String parameter that keeps track of the leading spaces for each line of output. Start it out with the value "" and then concatenate a String of spaces to create the indentation String parameter for the recursive calls on both subtrees.

In the file Startup.java, create an instance of a TreeMapping, and pass it to the test procedure. Verify that the output is correct. Look at the printed values of the mapping to be sure that the representation invariant is being preserved by your implementation.



Last modified 23:35:40 CST 01 April 1999 by Ron K. Cytron