/** Determines whether a key is valid. */
  protected void checkKey(Object k) {
    if (k == null) throw new InvalidKeyException("Invalid key: null.");
  }
  /** Hash function applying MAD method to default hash code. */
  public int hashValue(Object key) {
    return Math.abs(key.hashCode()*scale + shift) % N;
  }
  /** Returns the number of entries in the hash table. */
  public int size() { return n; }
  /** Returns whether or not the table is empty. */
  public boolean isEmpty() { return (n == 0); }
  /** Helper search method - returns index of found key or -index-1,
   * where index is the index of an empty or available slot. */
  protected int findEntry(Object key) throws InvalidKeyException {
    int avail = 0;
    checkKey(key);
    int i = hashValue(key);
    int j = i;
    do {
      if (A[i] == null)   return -i - 1;  // entry is not found
      if (A[i] == AVAILABLE) {	// bucket is deactivated
	avail = i;		// remember that this slot is available
	i = (i + 1) % N;	// keep looking
      }
      else if (T.isEqualTo(key,A[i].key()))  // we have found our entry
	return i;
      else // this slot is occupied--we must keep looking
	i = (i + 1) % N;
    } while (i != j);
    return -avail - 1;  // entry is not found
  }
  /** Returns the value associated with a key. */
  public Object get (Object key) throws InvalidKeyException {
    int i = findEntry(key);  // helper method for finding a key
    if (i < 0) return null;  // there is no value for this key
    return A[i].value();     // return the found value in this case
  }