// Hash Table using ** Open Addressing ** public class HashTableOA implements Dictionary { // Entry in the hash table using open addressing (no link field) private class Entry { K key; // Key V value; // Value public Entry(K k, V v) // Constructor { key = k; value = v; } public String toString() { return "(" + key + "," + value + ")"; } } public Entry[] bucket; // Hash table public int capacity; // capacity == bucket.length int NItems; // # items in hash table // MAD formula: ((a * HashCode + b) % p ) % M public int MAD_p; // Prime number in the Multiply Add Divide alg public int MAD_a; // Multiplier in the Multiply Add Divide alg public int MAD_b; // Offset in the Multiply Add Divide alg public int index_for_key; // = ((a * HashCode(key) + b) % p ) % M public Entry AVAILABLE = new Entry(null, null); // Special entry to // mark deleted entries public HashTableOA(int M) { bucket = (Entry[]) new Entry[M]; // Create a hash table of size M // Can't use "new Entry[M]" ! capacity = bucket.length; // Capacity of this hash table NItems = 0; // # items in hash table MAD_p = 109345121; // We pick this prime number... MAD_a = 123; MAD_b = 456; } /* =============================================================== Hash function for the hash table: 1. uses the Hash Code from Java 2. uses the MAD compression function on the hash code hash index = [ (a*HashCode + b) % p ] % N =============================================================== */ public int hashValue(K key) { int x = key.hashCode(); // key has a built-in hashCode() !!! return ((Math.abs(x*MAD_a + MAD_b) % MAD_p) % capacity); } /* ****************************************************************** Hash table methods ****************************************************************** */ public int size() { return( NItems ); } public boolean isEmpty() { return( NItems == 0 ); } /* --------------------------------------------------------------- findEntry(k): find bucket that contains key k If k is found: returns index of bucket for key k If k not found: returns -1 AND remembers first available entry --------------------------------------------------------------- */ int firstAvailEntry; int lastIndex; public int findEntry(K k) { int hashIdx = hashValue(k); // Get hash index using key k int start = hashIdx; // Remember the start index firstAvailEntry = -1; // First Available entry not found lastIndex = -1; // Last index is not valid do { Entry e; e = bucket[hashIdx]; if ( e == null ) { lastIndex = hashIdx; // Remember last index checked return -1; // Not found } if ( e != AVAILABLE && e.key.equals(k) ) return hashIdx; // Found if ( e == AVAILABLE && firstAvailEntry == -1 ) firstAvailEntry = hashIdx; // Remember the first avail // Slot is occupied by an entry that is not equal to k // Do linear search hashIdx = (hashIdx+1)%capacity; } while (hashIdx != start); // If we exit while loop with (hashIdx == start), key is not found return -1; } /* ------------------------------------------------------ put(k,v): if key k found: update corresponding value otherwise: insert (k,v) ------------------------------------------------------ */ public void put(K k, V v) { // Dictatic: good to show student the hash index int hashIdx = hashValue(k); System.out.println(k + " --> bucket: " + hashIdx); int buckIdx = findEntry(k); if ( buckIdx >= 0 ) // Key k was found in bucket buckIdx bucket[buckIdx].value = v; // Update value else if ( firstAvailEntry >= 0 ) // k not found, AVAIL was found { bucket[firstAvailEntry] = new Entry(k, v); // Enter (k,v) there NItems++; } else if ( lastIndex >= 0 ) // k not found, lastIndex valid { bucket[lastIndex] = new Entry(k, v); // Enter (k,v) there NItems++; } else System.out.println("Hash table full: (" + k + "," + v + ") not inserted"); } /* ------------------------------------------------------ get(k): if key k found, return corresponding value otherwise: return null ------------------------------------------------------ */ public V get(K k) { // Dictatic: good to show student the hash index int hashIdx = hashValue(k); System.out.println(k + " --> bucket: " + hashIdx); int buckIdx = findEntry(k); if ( buckIdx >= 0 ) // Key k was found in bucket buckIdx return bucket[buckIdx].value; else return null; } /* ---------------------------------------------------------------- remove(k): if key k found, remove Entry with k and return value otherwise: do nothing and return null ------------------------------------------------------ */ public V remove(K k) { // Dictatic: good to show student the hash index int hashIdx = hashValue(k); System.out.println(k + " --> bucket: " + hashIdx); int buckIdx = findEntry(k); if ( buckIdx >= 0 ) // Key k was found in bucket buckIdx { V ret = bucket[buckIdx].value; bucket[buckIdx] = AVAILABLE; NItems--; return ret; } else return null; } // Return string representing item in hash bucket e public String toString(Entry e) { if ( e == null ) return null; else if ( e == AVAILABLE ) return "AVAILABLE"; else return e.toString(); } public String toString() { String s = ""; for (int i = 0; i < bucket.length; i++) s = s + i + ": " + toString(bucket[i]) + "\n"; return s; } }