/**
  * Associates key k with value v in bucket with hash value h, returning the previously associated
  * value, if any.
  *
  * @param h the hash value of the relevant bucket
  * @param k the key of interest
  * @param v the value to be associated
  * @return previous value associated with k (or null, if no such entry)
  */
 @Override
 protected V bucketPut(int h, K k, V v) {
   UnsortedTableMap<K, V> bucket = table[h];
   if (bucket == null) bucket = table[h] = new UnsortedTableMap<>();
   int oldSize = bucket.size();
   V answer = bucket.put(k, v);
   n += (bucket.size() - oldSize); // size may have increased
   return answer;
 }
 /**
  * Removes entry having key k from bucket with hash value h, returning the previously associated
  * value, if found.
  *
  * @param h the hash value of the relevant bucket
  * @param k the key of interest
  * @return previous value associated with k (or null, if no such entry)
  */
 @Override
 protected V bucketRemove(int h, K k) {
   UnsortedTableMap<K, V> bucket = table[h];
   if (bucket == null) return null;
   int oldSize = bucket.size();
   V answer = bucket.remove(k);
   n -= (oldSize - bucket.size()); // size may have decreased
   return answer;
 }
 /**
  * Returns value associated with key k in bucket with hash value h. If no such entry exists,
  * returns null.
  *
  * @param h the hash value of the relevant bucket
  * @param k the key of interest
  * @return associate value (or null, if no such entry)
  */
 @Override
 protected V bucketGet(int h, K k) {
   UnsortedTableMap<K, V> bucket = table[h];
   if (bucket == null) return null;
   return bucket.get(k);
 }