CS302 -- Lab 4


Lab Objective

The objective of this lab is threefold:
  1. To give you experience using inheritance to declare an interface for a data structure and then creating subclasses that implement the data structure, and

  2. To give you experience using templates.

  3. To give you experience writing makefiles


Problem Statement

You will create an abstract class for a Search data structure and then implement this Search data structure using dlists and hash tables. You will test your implementations by reading records from an input file, inserting the records into your search data structure, and then performing find and delete operations on the search data structure. dsearch is a compiled binary that you can run to see what your output should look like. For example, try:
/ruby/homes/ftp/pub/bvz/classes/cs302/bin/dsearch
and follow the instructions for entering queries. Warning: dsearch expects a file named roster to be present in the directory in which you type the command. Hence you should either copy the roster file from the lab4 directory to your own directory before typing the command or you should cd to the cs302 bin directory.

Notice that dsearch does not read the roster file from stdin nor does it take it as an argument on the command line. As you will see later, the roster file is hardcoded as a constant.

In order to manage the compilation and linking of your files for this assignment, you will also create and hand in a makefile.


Setting up

You should copy the following files from the /ruby/homes/ftp/pub/bvz/classes/cs302/labs/lab4 directory to your directory:

Search Data Structure

An abstract data type for searching should be able to support three basic operations:

  1. Insert(key, record): Insert a record with the given key into the structure. You may assume that all keys are unique (i.e., there will be no duplicate keys in the file. You may also assume that the record contains the key and that the key is being passed as an argument for the convenience of the implementor.

  2. Remove(key): Delete the record associated with this key from the structure or indicate that no record containing this key is in the structure.

  3. Find(key): Return the record associated with this key or an indication that a record with this key is not in the structure.

In this part of the lab you will write an abstract class declaration for a search type, write dlist and hash table implementations, and test the implementations.

Format of the Input File

The input file for this problem consists of a roster of football players. The format of the input file is:

last name  first name   height   position   year    state    hometown   
 (string)   (string)   (string)  (string) (string) (string)  (one or more
                                                              strings)
An example line would be:
Colquitt Jerry  6.4     QB      Sr      Tennessee       Oak Ridge, TN
An example input file can be found in roster. You cannot make any assumptions about how many lines of data are in the input file. You must read in the input file using the Fields class.

Format of the Output

Our driver program produces the output for you so you do not have to worry about formatting the output.

The Search Key

The key for each entry in the input file consists of a first name and a last name. The search data structure will expect the first name and last name to be packaged into an object of type Name that has the following public interface:

class Name {
  public:
    Name(string fname, string lname);
    Name(const Name &);      // copy constructor
    bool isEqual(Name key);  // returns true if the parameter key matches
                              // this object's name
    bool lessThan(Name key); // returns true if this object's name is less
                              // than the parameter key.
    int hash(int tableSize);  // returns a hash value for the name
};
You will need to complete the declaration of this class by filling in the protected data members. You will also need to write the methods for this class. Two keys are equal if both their last names and first names are identical. One key is less than another key either if: 1) its last name is less than the other key's last name, or 2) its last name is equal to the other key's last name but its first name is less than the other key's last name. For example, "Jamal Lewis" is less than "Lennox Lewis" since the last names are identical and "Jamal" is less than "Lennox". Strings support the < and == operators so you can compare strings using these two operators.

You should modify the partial declaration for Name that can be found in Roster.h. You should put your method definitions for Name in Name.cc. The hash method has already been defined for you in Name.cc.

Storing A Line Of Data

You will need to store each line of input into an object of type RosterRecord. A RosterRecord needs to support the following public interface:

class RosterRecord {
  public:
    RosterRecord(string fname, string lname, string ht,
	         string pos, string yr, string players_team, string home);
    string getLastName();  // returns the player's last name
    string getFirstName(); // returns the player's first name
    string getHeight();    // returns the player's height
    string getPosition();  // returns the player's position
    string getYear();      // returns the player's year
    string getTeam();      // returns the player's team
    string getHometown();  // returns the player's hometown 
    Name getKey();         // packages the last name and first name
                           // into a name object and returns it
}
You will need to complete the declaration of this class by filling in the protected data members. You will also need to write the methods for this class. The declaration can be found in Roster.h. The method definitions should be placed in RosterRecord.cc.

One complication you will face is that the hometown may consist of multiple fields. You will need to concatenate these fields together to form one string. You can use the string class's += operator to do concatenation. For example:

string a = "Hello";
string b = "World";
string c += a + " ";
       c += b;  // c = "Hello World"
Remember to put blankspaces (" ") between the fields.

Interface for the Search Type

Here is the declaration for the abstract search type (the declaration can also be found in search.h):
class SearchType {
  public:
  virtual ~SearchType() {}
  virtual void insert(Name key, RosterRecord *value) = 0;
  
  // remove returns true if it successfully removes a record with this
  // key from the search structure. remove returns true if it cannot
  // find a record with this key in the search structure.
  virtual bool remove(Name key) = 0;  

  // find returns a pointer to a RosterRecord if it finds a record with
  // this key in the search structure. find returns 0 (i.e., the null
  // pointer) if it cannot find a record with this key in the search structure.
  virtual RosterRecord *find(Name key) = 0;
};

Dlist Implementation of SearchType

You should declare a subclass of SearchType called DlistSearch and add its declaration to search.h. DlistSearch should support exactly the same public interface as SearchType, and in addition it should add the following constructor declaration:

DlistSearch(); // performs any necessary initialization
The DlistSearch class should be implemented using a doubly linked list. A template Dlist class has been provided for this purpose. Notice that search.h already contains the appropriate include file for the Dlist template class. The Dlist template class takes one type argument, which is the type of the value being stored in the Dlist. For example:
Dlist x;    // A dlist that contains integers
Dlist y; // A dlist that contains pointers to Names
You should place your method definitions for DlistSearch in DlistSearch.cc.

Hash Table Implementation of SearchType

You should declare a subclass of SearchType called HashTableSearch and add its declaration to search.h. HashTableSearch should support exactly the same public interface as SearchType, and in addition it should add the following constructor declaration:

HashTableSearch(int tableSize); // performs any necessary initialization.
                                // tableSize is the desired hash table
				// size.
The HashTableSearch class should be implemented using a hash table. A template HashTable class has been provided for this purpose. The search.h file already contains the appropriate include file for the HashTable template class.

The HashTable template class takes two type arguments, which are the type of the key and the the type of the value being stored in the hash table. For example:

HashTable x;  // A hash table that stores pointers to
                                // personnel records and which uses an
				// integer as a key
The HashTable class assumes that the value type contains a method called getKey that returns the value's key and that the key type contains a method called hash that returns the key's hash value. You should look at the top of the HashTable.h file to see how the HashTable class is meant to be used and what arguments must be passed to its methods. Although you may look at the protected part of HashTable and at HashTable.cc, you are not expected to know how the HashTable is implemented (indeed you are not supposed to know!). You should place your method definitions for HashTableSearch in HashTableSearch.cc.

Testing Your Implementations

In order to test your implementations of DlistSearch we have provided a driver program and placed it in dsearch.cc. You will create a driver program called hsearch.cc to test the HashTableSearch structure. You will find that because of inheritance, the two files will be identical except for one line of code. This should show you how easy it is to switch implementations when both implementations use the same interface.

The driver program is supposed to read in the roster file, store the records in the roster file into the appropriate search structure, and then perform queries on these search structures. The querying and output formatting code have already been written for you. You will need to write the code to read lines from the roster file, convert the lines to RosterRecords, and insert the records into the search structure. The name of the roster file has been hardcoded into the program using a constant called INPUT_FILE. Hardcoding the file name may seem somewhat inflexible but it is done in many production, data processing systems because the names of the files are fixed in advance and it prevents a user from incorrectly specifying a file name.

In sum, for this portion of the lab you must:

  1. Complete the code in dsearch.cc file by inserting your code at the point labeled YOUR CODE GOES HERE.

  2. Copy your dsearch.cc file to hsearch.cc and change a line of code so that hsearch.cc creates a HashTableSearch structure.

What to Hand In

You should mail to Hui (ji@cs.utk.edu) a file created by /sunshine/homes/bvz/courses/302/bin/302submit. The file should be named username.lab where username is your username. For example, if I were submitting the lab, the file would be named bvz.lab. You will be sending your TA the following files: The makefile should create the executables dsearch and hsearch.