This completes the implementation of the ProbingHashTable abstract class. Nothing can be instantiated, however, until we decide how the findIndex method is to be implemented. This is the role of the QuadraticProbingTable and DoubleHashingTable extensions of the ProbingHashTable class.
Implementations of the QuadraticProbingTable and DoubleHashingTable classes are shown in Figures 11.6 and 11.7.
public class QuadraticProbingTable extends ProbingHashTable {
private static final int CAPACITY = 1;
private static final double LOADFACTOR = 0.5;
public QuadraticProbingTable(int capacity, double loadFactor) {
super(capacity, loadFactor);
if (loadFactor > 0.5) {
throw new IllegalArgumentException("load factor exceeds 0.5");
}
}
public QuadraticProbingTable(int capacity) {
super(capacity, LOADFACTOR);
}
public QuadraticProbingTable() {
super(CAPACITY, LOADFACTOR);
}
protected final int findIndex(Object key) {
int code = key.hashCode() & Integer.MAX_VALUE;
int length = table.length;
int index = code % length;
int probe = 1;
while (table[index] != null && !(table[index].key.equals(key))) {
index += probe;
if (index >= length) {
index -= length;
}
probe += 2;
}
return index;
}
}
|
public class DoubleHashingTable extends ProbingHashTable {
private static final int CAPACITY = 1;
private static final double LOADFACTOR = 0.5;
public DoubleHashingTable(int capacity, double loadFactor) {
super(capacity, loadFactor);
}
public DoubleHashingTable(int capacity) {
super(capacity, LOADFACTOR);
}
public DoubleHashingTable() {
super(CAPACITY, LOADFACTOR);
}
protected final int findIndex(Object key) {
int code = key.hashCode() & Integer.MAX_VALUE;
int length = table.length;
int index = code % length;
int probe = 1 + (code % (length - 1));
while (table[index] != null && !(table[index].key.equals(key))) {
index += probe;
if (index >= length) {
index -= length;
}
}
return index;
}
}
|
Implementation of the findIndex method is very similar in the two cases. This method has to find the index of a key, if the key is present, or the place at which to insert the key, if it is absent. Note the line
int code = key.hashCode() & Integer.MAX_VALUE;The hashCode method is defined for every Java Object. The value returned by hashCode is an integer, but it may be negative. The effect of performing the bitwise & operation is to ensure that code is a non-negative number. Since
Integer.MAX_VALUE has a 1 in every bit except the sign bit, where it has
0, this just changes the sign bit of the
hashCode value if it is 1, i.e. if the
hashCode value is negative. The effect is to add The initial value of index is defined to be the remainder of code modulo table.length. If the table entry at that index is empty, or if it already holds the key in question, we are finished. Otherwise we must enter the while loop and continue probing until we either find the key or else an empty place. Both methods increment index by probe each time around the loop. The only difference is that, for the QuadraticProbingTable class, the probe is incremented by 2 each time around the loop, so that successive probes are at
h, h+1, h+4, h+9, h+16, h+25, ...the differences between these being 1, 3, 5, 7, 9 etc. For the DoubleHashingTable class, the probe is fixed and is defined as
1+(code%(length-1)).
As discussed previously, this depends on the key to be
inserted.
If index would be out of array bounds, after being incremented by probe, we wrap around to the beginning by subtracting length. Note that probe itself is clearly less than length for DoubleHashingTable.findIndex. For QuadraticProbingTable.findIndex, it can be shown that the while loop will always terminate before probe exceeds length, provided length is prime and loadFactor is no greater than 0.5.