Hashing
How It Works
Once again, you re-used the tests defined in AbstractHashtableTestCase, this time implementing createTable() to return an instance of a BucketingHashtable. Notice the extra constructor parameter — 0.75f. This is the load factor, which in this case specifies that the hash table should increase in size anytime the number of values stored reaches 75% of the number of available buckets:
package com.wrox.algorithms.hashing;
public class BucketingHashtableTest extends AbstractHashtableTestCase { protected Hashtable createTable(int capacity) {
return new BucketingHashtable(capacity, 0.75f);
}
}
Bucketing is a little more complex than linear probing, so the implementation class requires a little more explanation.
The BucketingHashtable class records the load factor, for later use, and an array of buckets. You may have noticed in the “Understanding Hashing” section that the buckets looked a lot like linked lists, and that’s exactly what you’ve used for your buckets here. The number of buckets to use — initialCapacity — is specified at construction time along with the desired load factor:
package com.wrox.algorithms.hashing;
import com.wrox.algorithms.iteration.Iterator; import com.wrox.algorithms.lists.LinkedList; import com.wrox.algorithms.lists.List;
public class BucketingHashtable implements Hashtable { private final float _loadFactor;
private List[] _buckets;
public BucketingHashtable(int initialCapacity, float loadFactor) { assert initialCapacity > 0 : “initialCapacity can’t be < 1”; assert loadFactor > 0 : “loadFactor can’t be <= 0”;
_loadFactor = loadFactor;
_buckets = new List[initialCapacity];
}
...
}
The method maintainLoad() simply checks the current load. If the desired load has been exceeded, then a resize is necessary to spread the values over a larger number of buckets. The resize() method works in a similar way to the method of the same name in LinearProbingHashtable: A new hash table is created into which all the values are added, and then the new bucket array is used to replace the existing one. Each time a resize is performed, the capacity doubles. You could choose any value for this, but it always comes down to a trade-off between space and time. The smaller the increment, the more often a resize will be required; the larger the increment, the more wasted space.