package genDict;
import genListFW.*;
/**
* 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
* @author Dung X. Nguyen ("generifier")
* @since 03/23/05
*/
public class DictHash<K, V> implements IDictionary<K, V> {
/*
* Initialize _table to reference a single-element array of
* IDictionary, containing in its single element a reference to an
* empty DictLRS.
*/
private IDictionary<K, V>[] _table = new DictLRS[1];
private int _tableOccupancy = 0;
/*
* An IList factory used to linearalize each internal DictLRS and
* resize the _table array.
*/
private IListFactory< DictPair<K, V> > _lf;
/*
* An upper bound on the load factor.
*/
private double _loadFactor;
public DictHash(IListFactory< DictPair<K, V> > lf, double
loadFactor) {
_table[0] = new DictLRS<K, V>();
_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<K, V>();
_tableOccupancy = 0;
}
/**
* Returns true if the dictionary is empty and false otherwise.
*/
public boolean isEmpty() {
return _tableOccupancy == 0;
}
/**
* Returns false always.
*/
public boolean isFull() {
return false;
}
/**
* Returns an IList of DictPair<K, V>s corresponding to the entire
* contents of the dictionary.
*
* Note that the elements are not in order.
*/
public IList< DictPair<K, V> > elements(final IListFactory<
DictPair<K, V> > lf) {
IList< DictPair<K, V> > l =
lf.makeEmptyList();
for (int i = 0; i < _table.length; i++)
l = _table[i].elements(lf).execute(new
IListAlgo<DictPair<K, V>, IList< DictPair<K, V> >, IList< DictPair<K, V> > >() {
public IList<
DictPair<K, V> > emptyCase(IMTList<? extends DictPair<K, V> > host, IList<
DictPair<K, V> >... input) {
return input[0];
}
public IList<
DictPair<K, V> > nonEmptyCase(INEList<? extends DictPair<K, V> > host, IList<
DictPair<K, V> >... input) {
return lf.makeNEList(host.getFirst(),(IList< DictPair<K, V> >)host.getRest().execute(this,
input[0]));
}
}, l);
return l;
}
/**
* Returns the DictPair<K, V> with the given key. If there is not
* a DictPair<K, V> with the given key, returns null.
*
* Returns a DictPair<K, V> 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 DictPair<K, V> found
*/
public DictPair<K, V> lookup(K 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 the expected case as we amortize the cost
* of doubling the hash table over subsequent insert()'s.
* The worst case is O(n) since no duplicates are allowed.
*
* @param key the key to insert
* @param value the value to insert
*/
public void insert(K key, V 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<K, V>();
for (i = 0; i
< _table.length; i++) {
_table[i].elements(_lf).execute(new IListAlgo<DictPair<K, V>, Object, Object>()
{
public Object emptyCase(IMTList<? extends DictPair<K, V> > host, Object... nu) {
return null;
}
public Object nonEmptyCase(INEList<? extends DictPair<K, V> > host, Object... nu)
{
DictPair<K, V> pair = (DictPair<K, V>) host.getFirst();
int index = pair.getKey().hashCode() % newTable.length;
newTable[index].insert(pair.getKey(), pair.getValue());
return host.getRest().execute(this);
}
});
}
_table =
newTable;
}
int index = key.hashCode() % _table.length;
_tableOccupancy++;
_table[index].insert(key, value);
}
/**
* Removes the DictPair<K, V> with the given key and returns it.
* If there is not a DictPair<K, V> 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 DictPair<K, V> removed
*/
public DictPair<K, V> remove(K key) {
int index = key.hashCode() % _table.length;
DictPair<K, V> 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();
}
}