As mentioned in the pre-lab reading, the goal of this lab is to practice writing generic classes, and secondarily to practice writing nested classes. Many parts of this will be similar to Project 3, so the emphasis in this description will be on what is different.
As usual, make a directory for this lab. Copy the following code from the public directory.
cp -r /homes/tvandrun/Public/cs245/lab7/. .
Open Eclipse and make a new project from the existing source in your directory.
Try running the JUnit tests in SLMTest.java.
The tests emptyContainsKey,
emptyRemove, and
emptyGet should run
"by luck" out of the box.
Complete the following steps in order, making sure that the appropriate JUnit tests pass at each step.
In the class ComparatorFactory,
you'll see a stub for a method lexStringComparator
that returns a comparator for
strings.
The class LexComparatorTest is a JUnit test
that tests the comparators returned by that method.
Finish the lexStringComparator method
(just change one line)
so that it returns a comparator that compares strings lexicographically
(hint: that's the same way that String.compareTo()
would compare them).
Make sure that all the tests in LexComparatorTest
pass.
First, try running the JUnit test suit SLMStringTest.
Three test, emptyContainsKey, emptyRemove,
and emptyGet should pass out of the box "by luck".
Open the class SortedListMap.
You can see the given code, including dummy methods and method stubs.
There is also a stub for a Node class and an instance variable
for the head node.
The node class is a non-static member class, so it is
implicitly generic since SortedListMap is generic.
Your present task is
Node class.
Unfortunately no new JUnit tests will pass after this, but make sure that the ones that were passing before still pass.
Write the method findNode() that will
return the node associated with the given key, or
null if none exists.
Use the comparator to compare keys.
This will make putContainsKey,
putGet, and putReplace
pass.
Write an iterator for this that will return the keys. Do this as an anonymous inner class. Make every effort to do this without looking at in-class examples.
This should make emptyIterator,
and populatedIteratorIgnoreOrder pass.
Now the really interesting one. You were given a put method, but it doesn't work right. Re-write this method so that it overwrites the association for the given key (if it already exists), or puts a new association in the right order using the comparator otherwise.
Doing this correctly will make the test populatedIterator
pass.
Now write the remove() method.
Since this will be almost verbatim from what you did in project 3,
I will give you most of the code for this, for the sake of time.
You need to (a) talk through this with your partner and make sure you understand
every line, and (b) fix the missing pieces
(do not use == or equals(),
and make sur eyou understand why not):
public void remove(K key) {
if (head == null) return;
else if (/* some condition */) head = head.next;
else {
Node current = head;
while (current.next != null && /* some other condition */)
current = current.next;
if (current.next != null)
current.next = current.next.next;
}
}
All JUnit tests in SLMStringTest should now pass;
newly passed tests are populatedRemove and
removeIterator.
I've added a few more test cases (and a new version of
SLMDriver) since Wednesday.
Copy them with
cp ~tvandrun/Public/cs245/lab7-extra/* slm
(The above command assumes you are in your lab7
folder---or whatever you call it.
Just make sure that that the files in lab7-extra make it
to the slm folder.)
The advantage comparators have over comparables is that
since one can write many comparators for a class, one can have
many ways to order a class.
In ComparatorFactory finish the method
consonantsStringComparator
which compares two strings alphabetically, case-insensitive, looking only
at the consonants.
For example, Alice and Luca
would be considered equivalent because they have the same consonants,
ignoreing case.
Likewise blaaaaaaaaah and blah
would be considered equivalent,
and Azekah would come after Ziba.
Consider y to be a consonant.
This will take a bit of problem-solving, and you may want to
make use of methods from
Java's String class.
I can think of two approaches:
one makes use of String methods
toLowerCase(), indexOf(), and of course
charAt() and length();
the other approach makes use of toLowerCase(),
split() and compareTo().
When you have written this, test the comparator directly with
ConsComparatorTest.
Then make sure that your SortedListMap works just
as well with this comparator as with the other
by running SLMConStringTest, which is
very much like SLMStringTest except it uses the
new comparator.
Take a look at SLMDriver.
This program uses SortedListMap to associate
student records with grade records.
Look also at StudentRecord and GradeRecord,
which are pretty simple classes.
SortedListMap prints a grade report
for the students in the gradebook map using
one of three comparators for StudentRecords.
Write these three comparators as anonymous classes in
ComparatorFactory.
There are no JUnit tests for these;
instead, test each one by commenting out and uncommenting the appropriate
lines in SLMDriver and observing the results.
byNameComparator should order
StudentRecords primarily by last name (lexicographically),
secondarily by first name.
What this means is that if two people have the same last name,
then the comparator reverts to looking at the first name to disambiguate:
Janet Fitzgerald would come before Joey Fitzgerald.
byIdComparator should order
StudentRecords by their student ID.
(Hint: you can write this with a one-line compare()
method.
Hint hint: Thin about how you can use subtraction to
produce the right result.)
byCPOComparator should order
StudentRecords primarily by
CPO and secondarily by ID.
(Suppose that because of space constraints, some students share
a mailbox.)