package dict; import java.lang.*; import lrs.*; import listFW.*; /** * An IDictionary implemented using a hash table. Collisions are handled * using chaining. The chains are implemented using DictLRS. * * Uses the method hashCode() defined by class Object as the hash * function. Any class may override this method with a new * implementation. * * @author Alan L. Cox * @since 03/28/03 */ public class DictHash implements IDictionary { /* * Initialize _table to reference a single-element array of * IDictionary, containing in its single element a reference to an * empty DictLRS. */ private IDictionary[] _table = { new DictLRS() }; private int _tableOccupancy = 0; /* * An IList factory used to linearalize each internal DictLRS and * resize the _table array. */ private IListFactory _lf; /* * An upper bound on the load factor. */ private double _loadFactor; public DictHash(IListFactory lf, double loadFactor) { _lf = lf; _loadFactor = loadFactor; } /** * Clears the contents of the dictionary leaving it empty. * * Implemented by replacing the existing LRStruct with a new, * empty one. */ public void clear() { _table = new DictLRS[1]; _table[0] = new DictLRS(); _tableOccupancy = 0; } /** * Returns true if the dictionary is empty and false otherwise. */ public boolean isEmpty() { return _tableOccupancy == 0; } /** * Returns an IList of DictionaryPairs corresponding to the entire * contents of the dictionary. * * Note that the elements are not in order. */ public IList elements(IListFactory lf) { IList l = lf.makeEmptyList(); for (int i = 0; i < _table.length; i++) l = (AList)_table[i].elements(lf).execute(new IListAlgo() { public Object emptyCase(IEmptyList host, Object input) { return input; } public Object nonEmptyCase(INEList host, Object input) { return lf.makeNEList(host.getFirst(), (IList)host.getRest().execute(this, input)); } }, l); return l; } /** * Returns the DictionaryPair with the given key. If there is not * a DictionaryPair with the given key, returns null. * * Returns a DictionaryPair rather than the value alone so that * the user can distinguish between not finding the key and * finding the pair (key, null). * * This method is O(1) in the expected case and O(n) in the worst * case. * * @param key the key to lookup * @return the DictionaryPair found */ public DictionaryPair lookup(Comparable key) { int index = key.hashCode() % _table.length; return _table[index].lookup(key); } /** * Inserts the given key and value. If the given key is already * in the dictionary, the given value replaces the key's old * value. * * This method is O(1) in both the expected case and the worst * case if we amortize the cost of doubling the hash table over * subsequent insert()'s. * * @param key the key to insert * @param value the value to insert */ public void insert(Comparable key, Object value) { if (_tableOccupancy >= (_loadFactor * _table.length)) { int i; final IDictionary newTable[] = new IDictionary[2*_table.length]; for (i = 0; i < newTable.length; i++) newTable[i] = new DictLRS(); for (i = 0; i < _table.length; i++) { _table[i].elements(_lf).execute(new IListAlgo() { public Object emptyCase(AList host, Object input) { return null; } public Object nonEmptyCase(AList host, Object input) { DictionaryPair pair = (DictionaryPair) host.getFirst(); int index = pair.getKey().hashCode() % newTable.length; newTable[index].insert(pair.getKey(), pair.getValue()); return host.getRest().execute(this, input); } }, null); } _table = newTable; } int index = key.hashCode() % _table.length; _tableOccupancy++; _table[index].insert(key, value); } /** * Removes the DictionaryPair with the given key and returns it. * If there is not a DictionaryPair with the given key, returns * null. * * This method is O(1) in the expected case and O(n) in the worst * case. * * @param key the key to remove * @return the DictionaryPair removed */ public DictionaryPair remove(Comparable key) { int index = key.hashCode() % _table.length; DictionaryPair pair = _table[index].remove(key); if (pair != null) _tableOccupancy--; return pair; } /** * Returns a string representing the contents of the dictionary. */ public String toString() { return elements(_lf).toString(); } }