Graphic by Keith Ohlfs

CS111, Wellesley College, Spring 1998

Problem Set 10

Due: Thursday, May 7 by 4:00 p.m.

[CS111 Home Page] [Syllabus] [Students] [Lecture Notes] [Assignments] [Programs] [Documentation] [Software Installation] [FAQ] [CS Dept.] [CWIS]


Reading Assignment:

About this Problem Set

The purpose of this problem set is to give you practice with arrays, linked lists, loops and data abstraction.

There are 3 pieces to this problem set: laboratory assignment 1, laboratory assignment 2 and the homework assignment. There are two laboratory assignments (but no pre-lab assignments) for this problem set. You are required to do all three pieces. We recommend that you do laboratory problem 1during your first lab section (on Monday April 27th or Tuesday April 28th) and laboratory problem 2 during your second lab section (on Monday May 4th or Tuesday May 5th). The homework problems may be started any time - you do not need to wait to complete lab assignment 2 to begin working on the homework problems.

All code for this problem set can be found in the ps10_programs folder, which you can download from the CS111 download folder.

How to turn in this Problem Set

Laboratory 1 Problems: Save the modified PostOffice.java file in the PostOffice programs folder. Upload the entire folder to your ps10 drop folder. Turn in a hardcopy of the PostOffice.java file and its output. Save the modified Palindromes.java file in the Palindromes programs folder. Upload the entire folder to your ps10 drop folder. Turn in a hardcopy of the Palindromes.java file and output.for each of the three pal methods (labeled clearly, as indicated in the problem description).

Laboratory 2: Save the modified PS10IntListOps.java file in the Lists programs folder. Upload the entire folder to your ps10 drop folder. Turn in a hardcopy of the PS10IntListOps.java file and its output.

Homework Problems :

For Homework Problem 1, save the modified TestRect.java file in the Data Abstraction programs folder. Upload the entire folder to your ps10 drop folder. Turn in a hardcopy of the TestRect.java file.

For Homework Problem 2, save the modified Database.java file (formerly named DatabaseDouble.java) in the Database programs folder. Upload the entire folder to your ps10 drop folder. Turn in a hardcopy of the Database.java file. Also, turn in the object diagram from Part 1, and for Part 2, a brief explanation of why it is not necessary to modify any methods other than those changed in Part 2, tasks 1--6.

Turn in only one package of hardcopy materials. Staple your files and outputs together with the cover page, and submit your hardcopy package by placing it in the box outside of Jennifer's office (E104, directly across from E101).

Reminders


Laboratory 1 Problem 1: PostOffice

Patty the postwoman became bored one night, and to break the monotony of the night shift, she carried out an experiment with a row of mailboxes in the post office. These boxes were numbered 0 through 149, and beginning with mailbox 1, she opened the doors of every second mailbox. Next, beginning with mailbox 2, she went to every third mailbox, opening its door if it was closed and closing it if it was open. Then she repeated this procedure with every fourth mailbox, then every fifth, and so on. When she was finished, she was surprised at the distribution of closed mailboxes. In this lab, we will write code to determine which ones these were. Download the PostOffice.java file from the CS111 file server. In the file, the mailboxes have been represented by an array of length 150 containing boolean values. In this array, the values true and false indicate that the corresponding mailbox is open and closed, respectively. You have several tasks:

Task 1: Note the declaration of the initializeBoxes method which is responsible for initializing all the mailboxes to be closed. Flesh out the body of this method.

Task 2: Note the declaration of the displayClosedBoxes method which is responsible for printing out the mailboxes that are closed. Flesh out the body of this method. When done, run your program to test that it works. You should see that all the mailboxes are closed.

Task 3: Note the declaration of the changeBoxes method which is responsible for carrying out the opening and closing of the mailboxes as described above. Flesh out the body of this method. You will find it helpful to use two nested loops for your solution. We will discuss the details of this in lab. You may also find the % operator useful. It takes two integer operands and returns the remainder of their division. For example, 4 % 3 evaluates to 1, 5 % 3 evaluates to 2 and 6 % 3 evaluates to 0. When done, run your program to test that it works. Print out your results to be turned in as hardcopy. What do you observe about the mailboxes at the end? How can you reason about this result?


Laboratory 1 Problem 2: Palindromes

Palindromes are words or phrases that read the same forward and backward. In this problem we represent words and phrases by an array of characters and we will explore different techniques for identifying palindromes. Download the Palindromes.java file from the CS111 file server. In the code you see an array defined (testMatrix) that stores six different words or phrases that are potential palindromes. Note that testMatrix is a two dimensional array of characters. Each row of the array stores one word or phrase. For a given row, the columns of the array store the individual characters of a word or phrase. Note further that the array is initialized with six different potential palindromes. The potential palindromes are expressed without punctuation and spaces, and are entirely capitalized. These assumptions greatly simplify the task of identifying a palindrome.

Task 1: Carefully study the code provided. Comment out the invocation of the processAll method in the start method and view the code with the Appletviewer. The code then simply displays the words and phrases that we will be testing as palindromes. Can you determine the word or phrase of each potential palindrome? Which potential palindromes are indeed palindromes? Study the display and processAll methods and understand them fully. In particular, pay attention to the indexing of the two dimensional array and the way that the array is passed as a parameter. Note that the processAll method invokes a method pal(char [ ] a) that returns a boolean value indicating whether or not a passed one dimensional array is a palindrome. In the code there are three pal method stubs. We will fill in each one using a different technique for calculating a palindrome. At any time, make only one pal method active by commenting out the remaining two using /* and */.

Task 2: Write the body of the first pal method. It calculates whether or not a word or phrase is a palindrome by comparing the first and last characters of the word or phrase, the second and second to last characters of the word or phrase, the third and third to last characters of the word or phrase and so on. If all pairs of characters are equal, then the word or phrase is a palindrome and the method returns true. Otherwise, the word or phrase is not a palindrome and the method returns false. Test your code and print out your results to be turned in as hardcopy. Label your output task 2.

Task 3: Write the body of the second pal method. It calculates whether or not a word or phrase is a palindrome by comparing the word or phrase to itself in reverse. If the two are equal, then the word or phrase is a palindrome and the method returns true. Otherwise, the word or phrase is not a palindrome and the method returns false. Test your code and print out your results to be turned in as hardcopy. Label your output task 3.

Task 4: Write the body of the shorterA method. It accepts an array a as an input parameter and returns a subarray of a that consists of the original array a minus its first and last characters. This method is called shorterA because this subarray will be shorter than the original array by 2 characters. Note that this method returns an array.

Task 5: Write the body of the third pal method. It calculates the palindrome recursively and makes use of the shorterA method. Test your code and print out your results to be turned in as hardcopy. Label your output task 5.


Laboratory 2: IntList Methods

To begin this laboratory, download the Lists programs folder from the CS111 file server. The file IntListOps.java contains the integer list methods that we discussed in class.

Executing the applet IntListOpsTest.html gives a window in which you can see the results of various test cases involving the methods in IntListOps.java. Pressing the Run button displays the test results. The printed representation of lists has the elements in square brackets separated by commas. For instance, the list of numbers 3, 2, and 5 is displayed as [3, 2, 5] In this laboratory, you will define three recursive methods that manipulate integer lists. Skeletons for these methods appear in the file PS10IntListOps.java. This file is configured so that you can use head, tail, prepend, etc as abbreviations for IntList.head, IntList.tail, IntList.prepend, etc. You can test your methods by executing the PS10IntListOpsTest.html applet, which runs your methods on example lists.

Here are contracts and test case results for the three methods:

public static boolean isSorted(IntList L)
A recursive method that returns true if the integers in L are sorted from low to high, and false otherwise.

Examples:

isSorted([ ]) = true
isSorted([1]) = true
isSorted([1]) = true
isSorted([1, 1]) = true
isSorted([2, 1]) = false
isSorted([1, 2, 3, 4, 5]) = true
isSorted([1, 2, 3, 4, 0]) = false
isSorted([1, 5, 3, 4, 2]) = false

 

public static IntList remove(int i, IntList L)
A recursive method that r eturns a new list that contains all of the elements of L in the same order except for occurrences of i, which are removed.

Examples:

remove(0, [4, 2, 3, 4, 1, 3, 4, 2, 4, 3]) = [4, 2, 3, 4, 1, 3, 4, 2, 4, 3]
remove(1, [4, 2, 3, 4, 1, 3, 4, 2, 4, 3]) = [4, 2, 3, 4, 3, 4, 2, 4, 3]
remove(2, [4, 2, 3, 4, 1, 3, 4, 2, 4, 3]) = [4, 3, 4, 1, 3, 4, 4, 3]
remove(3, [4, 2, 3, 4, 1, 3, 4, 2, 4, 3]) = [4, 2, 4, 1, 4, 2, 4]
remove(4, [4, 2, 3, 4, 1, 3, 4, 2, 4, 3]) = [2, 3, 1, 3, 2, 3]

 

public static IntList removeDuplicates(IntList L)
A recursive method that r eturns a new list that contains exactly only one occurrence of each integer that occurs in L. The order of the integers in the resulting list does not matter.

Examples:

removeDuplicates([ ]) = [ ]
removeDuplicates([3, 5, 2, 1, 4]) = [3, 5, 2, 1, 4]
removeDuplicates([4, 2, 3, 4, 1, 3, 4, 2, 4, 3]) = [4, 2, 3, 1]


Homework Problem 1: Data Abstraction

In this problem we will consider the problem of representing a rectangle in two different ways. Begin the problem by downloading the file TestRect.java from the Data Abstraction folder on the CS111 file server. In the file there is a Java class Rect that represents rectangles. The class has the following constructor:

public Rect (int x, int y, int width, int height)

This constructor creates a rectangle with upper left coordinates x and y, width width and height height. A straighforward way to represent such a rectangle is to keep track of four integers: the x and y coordinates of the upper left corner, the width, and the height. The TestRect.java file includes a Java class that implements this representation called Rect.

Study the TestRect file. It includes two classes: TestRect and Rect. Note that in the TestRect class there are paint, area and draw methods defined. You do not have to understand these methods to do this problem and should not change them. View the TestRect .java file's output using the Appletviewer.

The goal of this problem is for you to implement an alternative representation for rectangles such that you can substitute your representation in place of the already defined Rect class (just studied) in the TestRect.java file and achieve the same exact output that you just observed.

One such alternative representation for rectangles is an array of Point objects that contains a Point for the upper left corner of the rectangle and a Point for the lower right corner of the rectangle. In the TestRect.java file, note that there is a second Rect class definition that has been commented out at the end of the file. Comment out the original Rect class definition that you just experimented with and uncomment out this second Rect class definition. Flesh out this second Rect class as indicated in the file. Note that it implements this alternative rectangle representation. In the constructor method, corners is an array of Point objects. In this method, you simply need to complete the two incomplete statements provided for you. You do not need to, and should not, write any other lines of code in this method. The remaining methods must also be fleshed out. You should expect their contents to be very short pieces of code. It also is important to recognize that the Rect constructor takes exactly the same arguments as before. Only the internal representation of the rectangle has changed. You can test your program by viewing TestRect.java with the Appletviewer. You should observe the exact output that you observed earlier with the original class definition.


Homework Problem 2: The Day-to-Day Database Crisis!

Now that you have mastered the basic elements of Java programming, you have decided to do some work as a programming consultant to earn a little extra spending money. You answer an ad from the Day-To-Day temporary employment agency concerning some troubles they are having with their employee database. The human resource department of Day-To-Day uses a simple database program (described below) that maintains the name and email address of each active temporary employee. Unfortunately, the creators of this database program only tested the program on small test databases and did not worry about how long certain operations would take on large databases. In particular, it turns out that the database program is rather inefficient at adding each new person, so that large databases can take a very long time to create. Your job is to rewrite a portion of the database code in a more efficient form so that large databases will be created more quickly. Because the company does not want to have to retrain its human resource staff to work with a new database program, they have asked you to modify the existing program so that it has the same behavior from the user's perspective, except that certain operations should be faster.

The Features of the Database Program

The database program used by Day-To-Day can be found in the Database programs folder in the CS111 download folder. Run the applet DatabaseWorld.html within this folder using the appletview. You will see that the program consists of a window with several buttons at the left as shown below:

If you press the Load DB File button, you will be prompted to select a database file using the usual Macintosh file dialog mechanism. All files ending in the extension .db are database files. The Database folder contains three such files: test4.db, test6.db, and test10.db. If you select test6.db, the database window will be updated to show the six personnel entries in this file, as shown below:

Each personnel entry has four fields: a last name, a first name, a middle name or initial (which may be empty), and an email name. An entry may be selected by clicking on it. At most one entry can be selected at any one time.

The other buttons manipulate the entries as described below.

You should play around with the applet to get a feel for these operations before attempting the rest of this problem.

The Database Class Interface

The database program is rather large. Fortunately, due to the wonders of data abstraction, it turns out that you only have to understand the Database class defined in the source code file Database.java. Instances of the Database class maintain an ordered collection of Person objects, each of which represents one entry in the database. The Database class is in some sense the heart of the database program --- all of the other classes in the program provide support for interacting with Database objects or the Person objects that they hold.

The Database class has the following interface:

Constructor:

public Database()
Create an empty database (one that contains no persons). 
 
Instance Methods:
 
public int size()
Return the number of persons in the database.
 
public void clear()
Make this database empty. 
 
public void add(Person p)
Add person p to the end of this database. 
 
public void remove(String s)
Remove the person with description string s from this database.
If no person in the database has description string s, do nothing. 
(The description string of a Person object is the entry string that 
appears in the database window. This string is produced by the 
String toString() method of the Person class. The 
boolean hasString (String s) method on the Person 
class is used to test if a person has a given description string.)
 
public void sort (Comparator comp)
Sort the entries of the database according to the comp object. A
Comparator object specifies the ordering of two Person objects via a
boolean lessThan (Person p1, Person p2) method. 
 
public void print()
Display the entries of the database in the stdout window. 
	
public void print(PrintStream ps)
Write the entries of the database to the print stream ps. 
This method is used to save databases to a file. 
	
public String [ ] entryList()
Return an array of description strings for the entries of the database.
The description strings have the same order as the database entries. 

The Database Class Implementation

There are zillions of ways to implement the Database class interface presented above. The implementation in the file Database.java represents a database with n entries as an array (named people) of n Person objects. You should study the code in Database.java to see how each of the above constructors and methods is implemented in terms of this representation. In particular, pay attention to the implementation of the add and remove methods. The add method adds a person p to the end of a database as follows:

The remove method removes the person with description string s as follows:

These operations do a lot of copying work every time an entry is added to or removed from the database. It turns out that loading a database with n entries from a file calls the add method n times. Because of all the copying involved, it can take a long time to load in a large database. We will see in CS230 that the loading process takes time quadratic in the size of the database --- i.e., it is proportional to the square of the size of the database. This is bad; we would like it to take time linear in the size of the database --- i.e., it should take time proportional to the size of the database.

The purpose of this problem is to explore an alternative representation of databases that makes add and remove more efficient.

Part 1: Object Diagrams

In this part of the problem, you will exhibit your understanding of the representation in Database.java by drawing an object diagram of a simple database. Consider the database constructed by the following code:

Database db = new Database();
Person p1 = new Person("Georgia", "", "Dome", "gdome");
Person p2 = new Person("Foo", "Bar", "Baz", "fbaz");
db.add(p1);
db.add(p2);

Draw a single object diagram showing the state of the database after the execution of all of the above statements. Observe these conventions:

Your diagram should have 3 local variables and 12 objects (the database object, the database array, two person objects, and eight string objects).

Part 2: An Alternative Database Representation

In this problem, you will implement an alternative database representation that improves the efficiency of the add and remove methods. One way to make the add method more efficient is to start with a database array that is a certain small size (for example 4 elements), instead of zero elements. You can then add entries without increasing the array size until you fill that array. When you reach the limit for that array, you can then create a new array that is double the size of the old array, and copy the old array into the new one (much like the current version of the program does). Thus, when you add the 5th person, you would:

You can then add people to your database without copying until you reach the ninth person to be added, at which time you can double the size of the array again. The strategy of doubling the size of the array rather than incrementing the size of the array every time it is full significantly reduces the number of copy operations that need to be performed in a sequence of add invocations. In fact, the doubling strategy changes the quadratic time load process into a linear time load process.

The remove method can be implemented as follows:

Note that a remove invocation never changes the size of the array in this strategy.

Note that the number of entries in this strategy is no longer equal to the length of the people array. To keep track of the database size, a database object must have an additional instance variable (call it count) that counts the number of entries in the database. The following invariant should be preserved by all the database operations:

To begin this problem, you should follow these steps:

  1. Download the Database programs folder to your local disk.
  2. Open Database.proj.
  3. Open Database.java by double clicking on the icon in the project window. Rename the class and constructor from Database to DatabaseIncrement. Save the file away as DatabaseIncrement.java.
  4. Open DatabaseDouble.java by double clicking on the icon in the project window. Rename the class and constructor from DatabaseDouble to Database. Save the file away as Database.java.

The file initially named DatabaseDouble is a skeleton for the alternative database representation. The above steps are necessary for replacing the original Database implementation by the alternative Database representation. Note that the original version is still available in DatabaseIncrement.java -- you may wish to refer to this file as you flesh out the skeleton. If you wish to install the original version again, you will have to undo steps 3 and 4.

For this problem, you will only need to accomplish the following tasks:

  1. Implement the Database() constructor. The initial people array should have length 4.
  2. Implement the size() method. You can test this method using the Print button, which prints out the size of the database along with the entries.
  3. Implement the clear() method. This should not change the size of the people array.
  4. Implement the add(Person p) method as outlined above. This should double the size of the people array only when the array is full of valid entries. You may wish to insert a call to System.out.println that indicates every time the array size is doubled. You can test this method via the Add button. You can also test add(Person p) and clear() together using the Load DB File button. This clears the database and adds the entries from the file one by one. You should try loading all the provided .db files.
  5. Implement the remove() method as sketched above. This method should not change the size of the people array. You can test this method via the Remove button.
  6. It is not necessary to modify any other methods other than the ones mentioned above. As part of your problem set, you should include a brief explanation why it is not necessary to modify any of the other methods.

Note: On the small databases provided, you will not be able to observe a noticeable speedup with the new implementation. If time permits, we will try to provide a larger file that makes the speedup clear.