Rev 100 | Blame | Compare with Previous | Last modification | View Log | RSS feed
//import chap09.list03.Map;// License: Public Domain (added on 07-11-2005)import java.io.*;import java.util.*;public class HashTable implements Map { // open addressingprivate Entry[] entries;//size is the total number of elements, including NIL//used is the total number of elements, NOT INCLUDING NILprivate int size, used;private float loadFactor;private final Entry NIL = new Entry(null,null); // dummyprivate int probeType; //holds the type of probing to use//variable to hold total number of collisions this run.//Definition: collision - the number of times we must jump to// get to the next null space in the table// This includes jumping NIL's////NOTE: will only be counted on inserting valuesprivate int collisions; //initialized to 0 by default//create a HashTable with a certain capacity (maximum items)//and a maximum load factor (if we exceed this we will rehash)public HashTable(int capacity, float loadFactor) {entries = new Entry[capacity];this.loadFactor = loadFactor; }//create a HashTable with a certain capacity (maximum items)//and a default load factor of 0.75public HashTable(int capacity) {this(capacity,0.75F);} //calls the HashTable( int, float ) constructor//create a default HashTable with default capacity (101 items) and//default load factor of 0.75public HashTable() {this(101); } //calls the HashTable( int ) constructor//Method to find a certain key in the HashTable//Precondition: key != null//Postcondition: return the entry's value if the key is found// otherwise return null for not foundpublic Object get(Object key) {int h=hash(key);for (int i=0; i<entries.length; i++) {int j = nextProbe(h,i);Entry entry=entries[j];if (entry==null) break;if (entry==NIL) continue;if (entry.key.equals(key)) return entry.value; // success}return null; // failure: key not found}//Method to add a key/value pair to the HashTable//Key - the value that gets hash() called on it. Should be unique (hopefully)//Value - the actual data that is to be stored.//Precondition: key != null//Postcondition: return null if the object was inserted sucessfully// return the value that was there if we updated a value// return null if the table overflows (should never happen,// but it is there just in case)public Object put(Object key, Object value) {if (used>loadFactor*entries.length) rehash();System.out.print(key); //print out the keyint h=hash(key); //hash the key//run once for each position in the Tablefor (int i=0; i<entries.length; i++) {//get the [first, next] place to try putting the valueint j = nextProbe(h,i);//get the Entry at j (where we want to put value)Entry entry=entries[j];//print the location we tried to place the valueSystem.out.print(" -> " + j);//if entry[j] == null then we have found a good place to put value!if (entry==null) {System.out.println(); //terminate the lineentries[j] = new Entry(key,value);++size;++used;return null; // insertion success}//if entry[j] == NIL then we must continue to probe for a new place,//otherwise we will confuse the remove() and get() methodsif (entry==NIL) { collisions++; continue; }//if entry[j].key == key then we need to update the recordif (entry.key.equals(key)) {Object oldValue=entry.value;entries[j].value = value;return oldValue; // update success}//if we get here, we have had a collision that is not a NIL,//and is not an Entry that needs updating, therefore it is something//else that hashes to the same value. Therefore we must increment the//collision countercollisions++;} //end for loopreturn null; // failure: table overflow} //end put()//Method to remove a key/value pair from the table.//This will leave a NIL behind//Precondition: key != null//Postcondition: return the old value if the key was found, then// put a NIL in it's place. return null if the key// was not found in the table.public Object remove(Object key) {int h=hash(key); //hash the key//run once for every place in the tablefor (int i=0; i<entries.length; i++) {//find the [first, next] place to put the valueint j = nextProbe(h,i);Entry entry=entries[j];//break out of the loop, since the key was not foundif (entry==null) break;if (entry==NIL) continue; //keep going, since we found a NILif (entry.key.equals(key)) { //we found the key we are looking for...Object oldValue=entry.value; //save value to returnentries[j] = NIL; //replace the value with a NIL--size; //decrement sizereturn oldValue; // success}}return null; // failure: key not found}//Method to access private variable size//Precondition: none//Postcondition: return sizepublic int size() {return size;}//Method to access private variable collisions//Precondition: none//Postcondition: return collisionspublic int collisions() {return collisions;}//Method to set the probeType variable////0 == Linear Probing (step size 1) DEFAULT//1 == Prime Probing (step size 3)//2 == Prime Probing (step size 5)//3 == Prime Probing (step size 7)//4 == Prime Probing (step size 11)//5 == Quadratic Probing//6 == Double Hashing////Precondition: 0 <= newValue <= 6//Postcondition: probeType will be changed//WARNING: Please do NOT change probeType while in a test runpublic void setProbeType( int newValue ) {//put in for safety, just in caseif( newValue < 0 || newValue > 6 ) { newValue = 0; }probeType = newValue;}//A private class which will hold a key/value pairprivate class Entry {Object key, value;Entry(Object k, Object v) { key=k; value=v; }}//our implementation of the hash() function. Takes the Object.hashCode() method//and chops off the sign bit//Precondition: None (we check for key == null)//Postcondition: throw an IllegalArgumentException() if the key == null// return an integer hash for the given keyprivate int hash(Object key) {if (key==null) throw new IllegalArgumentException();return (key.hashCode() & 0x7FFFFFFF) % entries.length;}//Method to implement linear probing//Precondition: h != null; i != null//Postcondition: return the next place to try and put the valueprivate int nextProbe(int h, int i) {int returnVal = 0; //set to zero to stop compiler errorswitch( probeType ) {case 0: //linear probingreturnVal = (h + i)%entries.length;break;case 1: //Prime Probing ( p=3 )returnVal = (h + (i * 3 ))%entries.length;break;case 2: //Prime Probing ( p=5 )returnVal = (h + (i * 5 ))%entries.length;break;case 3: //Prime Probing ( p=7 )returnVal = (h + (i * 7 ))%entries.length;break;case 4: //Prime Probing ( p=11 )returnVal = (h + (i * 11))%entries.length;break;case 5: //Quadratic ProbingreturnVal = (h + (i * i ))%entries.length;break;//I am aware that my implementation of Double Hashing (which follows) is//wasteful in terms of computation time (we must create the array "step"//each and every time this code is run. I did it this way to abstract the//method used to find the nextProbe() location from the put method.case 6: //Double Hashingint[] step = { 2,3,5,7,11 };int stepSize = step[h%4];returnVal = (h + (i * stepSize))%entries.length;break;}//return the final valuereturn returnVal;}//Method to rehash the entire table. This will get rid of NIL's//Precondition: none//Postcondition: entries will be twice the size plus one (ensures odd size)// all NIL will be gone// all values will be re-hash()edprivate void rehash() {Entry[] oldEntries = entries;entries = new Entry[2*oldEntries.length+1];for (int k=0; k<oldEntries.length; k++) {Entry entry=oldEntries[k];if (entry==null || entry==NIL) continue;int h=hash(entry.key);for (int i=0; i<entries.length; i++) {int j = nextProbe(h,i);if (entries[j]==null) {entries[j] = entry;break;}}}used = size;}}