// Hash Table using separate chaining public class HashTableSC implements Dictionary { // Entry contains next to chain into a list private class Entry { private K key; // Key private V value; // Value private Entry next; // Chain ! 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 HashTableSC(int M) { bucket = (Entry[]) new Entry[M]; // Create a hash table of size M // Note: can't use "new Entry[M]" capacity = bucket.length; // Capacity of this hash table NItems = 0; // # items in hash table // Initialize parameters for the hash function MAD_p = 109345121; // We pick this prime number... MAD_a = 123; // a = non-zero random number MAD_b = 456; // b = random number } /* =============================================================== 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 ] % M =============================================================== */ 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(key): find the Entry containing key in hash table Returns Entry object containing key Returns null if not found ------------------------------------------------------ */ public Entry findEntry(K k) { int hashIdx = hashValue(k); // Get hash index using key k Entry curr = bucket[hashIdx]; // h = head/first of linked list while (curr != null) { if ( curr.key.equals(k) ) return curr; curr = curr.next; } return null; } /* ------------------------------------------------------ put(k,v): if key k found: update corresponding value otherwise: insert (k,v) ------------------------------------------------------ */ public void put(K k, V v) { int hashIdx = hashValue(k); System.out.println(k + " --> bucket: " + hashIdx); Entry h = findEntry(k); if ( h != null ) h.value = v; // Update value else { // Add newEntry as first element in list at bucket[hashIdx] Entry newEntry = new Entry(k, v); newEntry.next = bucket[hashIdx]; bucket[hashIdx] = newEntry; NItems++; } } /* ------------------------------------------------------ get(k): if key k found, return corresponding value otherwise: return null ------------------------------------------------------ */ public V get(K k) { // This is not necessary, but enlightening to show student the hashIdx int hashIdx = hashValue(k); System.out.println(k + " --> bucket: " + hashIdx); // The get() method starts here.... Entry h = findEntry(k); if ( h != null ) return h.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) { int hashIdx = hashValue(k); // Base case 1: empty bucket if ( bucket[hashIdx] == null ) return null; // Base case 2: remove first elem (update bucket[hashIdx] if ( bucket[hashIdx].key.equals(k) ) { V ret = bucket[hashIdx].value; bucket[hashIdx] = bucket[hashIdx].next; NItems--; return ret; } // General case: search in list Entry previous = bucket[hashIdx]; Entry current = bucket[hashIdx]; while (current != null && !current.key.equals(k) ) { previous = current; current = current.next; } if ( current != null ) { previous.next = current.next; // Unlink current NItems--; // Accounting... return current.value; // Return value } return null; // Not found } // Return string representing item in hash bucket e public String toString(Entry e) { String out = ""; while ( e != null ) { out = out + " " + e.toString(); e = e.next; } return out; } public String toString() { String s = ""; for (int i = 0; i < bucket.length; i++) s = s + i + ": " + toString(bucket[i]) + "\n"; return s; } }