CS60 Data Structures HW-3 Homework #3 Hashing For this project we will be writing two hashing schemes (chaining and linear probing). You will need to write four classes: AbstractHashMap (super-class of the next two classes), ChainHashMap (implements linked list chain), LinearHashMap (implements linear probing on a single array), and TestHashMap (to text the whole thing). AbstractHashMap This abstract class will define: The protected symbolic constant (DEFAULT_BUCKETS) which is the number of buckets in the hash array if a default constructor is called (use 17 as the default value). The protected inner class (Entry) which will represent the data entry for the map. This class will contain the protected data members key and value. It will also contain the overridden methods equals() and toString(). The equals() method will only compare the key data member, the value data member will be ignored for this method. The format of the string returned by toString() will be: “<key(hashIndex) => value>” (see below regarding the hashIndex). The protected array (map) which holds the hashed entries. Since the chaining implementation will contain List entries and the linear implementation will contain Entry entries we will declare the array to be of type Object so that either type of objects will fit into the array. The protected integer number of buckets (nBuckets) to be allocated to the hash array. This value will be set by the constructor to be either the default value (defined above) or the parameter of the constructor. The protected integer number of elements currently stored in the hash map size). The protected method int getIndex(Object key) which calls the hashCode() method on the object key and then returns the value of the hash modulo the number of buckets in the hash array. The protected abstract method Entry getEntry(Object key) which will be defined by the derived classes. This method will return either the Entry object containing the key or the value null if the key is not found. The derived classes will implement this method as appropriate to their implementation. The protected abstract method void newEntry(Object key, Object value) which will be defined by the derived classes. This method will add a new entry to the map. We should assume that prior to calling this method the client code has called getEntry() and verified that the entry does not exist in the map. The derived classes will implement this method as appropriate to their implementation. Page 1 of 3 CS60 Data Structures HW-3 The public method int size() which returns the current number of elements in the map. The public method Object get(Object key) which calls getEntry() and returns the value of the Entry with the specified Key. This method is inherited by the derived classes and calls getEntry() polymorphicly. The public method Object put(Object key, Object newValue) which calls getEntry() to see if the entry already exists. If it does then the old value will be returned and the newValue will be set. If the entry does not already exist then it will call newEntry() to create the new entry and store it in the proper place. This method is inherited by the derived classes and calls getEntry() and newEntry() polymorphicly. The public method void display() which prints the size of the map and the contents of the elements of the map to System.out. Note: since Entry has a toString() method and List has a toString() method (a comma separated list of items inside square brackets ([…])), the hash map array elements can just be sent to the println() method which will handle the proper formatting. Note also: if any element is null then the println() method will display the string “null” which is what we want. See sample output report for proper formatting of data. ChainHashMap This concrete class extends the abstract class and will define: The default constructor. The constructor which takes an integer argument (number of buckets). The protected method Entry getEntry(Object key) which will return either the Entry object containing the key or the value null if the key is not found. The protected method void newEntry(Object key, Object value) which will add a new entry to the map. We should assume that prior to calling this method the client code has called getEntry() and verified that the entry does not exist in the map. All other methods are inherited from the abstract super-class. LinearHashMap This concrete class extends the abstract class and will define: The default constructor. The constructor which takes an integer argument (number of buckets). The protected method Entry getEntry(Object key) which will return either the Entry object containing the key or the value null if the key is not found. Page 2 of 3 CS60 Data Structures HW-3 The protected method void newEntry(Object key, Object value) which will add a new entry to the map. We should assume that prior to calling this method the client code has called getEntry() and verified that the entry does not exist in the map. All other methods are inherited from the abstract super-class. TestHashMap This class is given here: import java.util.Random; public class TestHashMap { public static final int RANGE = 100; public static final int NUM_ITEMS = 25; public static void main(String[] args) { ChainHashMap mc = new ChainHashMap(); LinearHashMap ml = new LinearHashMap(NUM_ITEMS * 2 + 3); Random rand = new Random(); Object key, value, oldValue; for (int i = 0; i < NUM_ITEMS; i++) { key = new Integer(rand.nextInt(RANGE)); value = Integer.toString(i); oldValue = mc.put(key, value); if (oldValue != null) System.out.println("Duplicate entry for key: " + key + ", was: " + oldValue + ", now: " + value); oldValue = ml.put(key, value); } mc.display(); System.out.println(); ml.display(); } } If you are interested in playing around with Java 5 generics, you can modify the above to generify the classes and make them more universal. Have fun! Page 3 of 3