920 lines
24 KiB
Java
920 lines
24 KiB
Java
|
package com.jwetherell.algorithms.data_structures;
|
||
|
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.List;
|
||
|
|
||
|
import com.jwetherell.algorithms.data_structures.interfaces.IMap;
|
||
|
|
||
|
/**
|
||
|
* Hash Map using either chaining or probing. hash map is a data structure that
|
||
|
* uses a hash function to map identifying values, known as keys, to their
|
||
|
* associated values.
|
||
|
*
|
||
|
* http://en.wikipedia.org/wiki/Hash_table
|
||
|
*
|
||
|
* @author Justin Wetherell <phishman3579@gmail.com>
|
||
|
*/
|
||
|
@SuppressWarnings("unchecked")
|
||
|
public class HashMap<K, V> implements IMap<K,V> {
|
||
|
|
||
|
public static enum Type { CHAINING, PROBING }
|
||
|
|
||
|
private HashMap<K,V> delegateMap = null;
|
||
|
|
||
|
private static class ChainingHashMap<K, V> extends HashMap<K, V> {
|
||
|
|
||
|
private float loadFactor = 10.0f;
|
||
|
private int minimumSize = 1024;
|
||
|
private int initialListSize = 10;
|
||
|
private List<Pair<K, V>>[] array = null;
|
||
|
private int size = 0;
|
||
|
|
||
|
/**
|
||
|
* Create a hash map with K as the hashing key.
|
||
|
*
|
||
|
* @param size
|
||
|
* initial size.
|
||
|
*/
|
||
|
public ChainingHashMap(int size) {
|
||
|
initializeMap(size);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a hash map with the default hashing key.
|
||
|
*/
|
||
|
public ChainingHashMap() {
|
||
|
initializeMap(minimumSize);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V put(K key, V value) {
|
||
|
return put(new Pair<K, V>(key, value));
|
||
|
}
|
||
|
|
||
|
public V put(Pair<K,V> newPair) {
|
||
|
int index = indexOf(newPair.key.hashCode());
|
||
|
List<Pair<K, V>> list = array[index];
|
||
|
V prev = null;
|
||
|
boolean exist = false;
|
||
|
// Do not add duplicates
|
||
|
for (Pair<K, V> p : list) {
|
||
|
if (p.key.equals(newPair.key)) {
|
||
|
prev = p.value;
|
||
|
p.value = newPair.value;
|
||
|
exist = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!exist)
|
||
|
list.add(newPair);
|
||
|
|
||
|
size++;
|
||
|
|
||
|
// If size is greater than threshold
|
||
|
int maxSize = (int)(loadFactor*array.length);
|
||
|
if (size >= maxSize)
|
||
|
increase();
|
||
|
|
||
|
return prev;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V get(K key) {
|
||
|
int index = indexOf(key.hashCode());
|
||
|
List<Pair<K, V>> list = array[index];
|
||
|
for (Pair<K, V> p : list) {
|
||
|
if (p.key.equals(key))
|
||
|
return p.value;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean contains(K key) {
|
||
|
return (get(key)!=null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V remove(K key) {
|
||
|
int index = indexOf(key.hashCode());
|
||
|
List<Pair<K, V>> list = array[index];
|
||
|
for (Pair<K, V> pair : list) {
|
||
|
if (pair.key.equals(key)) {
|
||
|
list.remove(pair);
|
||
|
size--;
|
||
|
|
||
|
V value = pair.value;
|
||
|
pair.key = null;
|
||
|
pair.value = null;
|
||
|
|
||
|
int loadFactored = (int)(size/loadFactor);
|
||
|
int smallerSize = getSmallerSize(array.length);
|
||
|
if (loadFactored < smallerSize && smallerSize > minimumSize)
|
||
|
reduce();
|
||
|
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public void clear() {
|
||
|
for (int i=0; i<array.length; i++)
|
||
|
array[i].clear();
|
||
|
size = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public int size() {
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
private void increase() {
|
||
|
// Save old data
|
||
|
List<Pair<K, V>>[] temp = this.array;
|
||
|
|
||
|
// Calculate new size and assign
|
||
|
int length = getLargerSize(array.length);
|
||
|
//System.out.println("increase from "+array.length+" to "+length);
|
||
|
initializeMap(length);
|
||
|
|
||
|
// Re-hash old data
|
||
|
for (List<Pair<K, V>> list : temp) {
|
||
|
for (Pair<K, V> p :list) {
|
||
|
this.put(p);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void reduce() {
|
||
|
// Save old data
|
||
|
List<Pair<K, V>>[] temp = this.array;
|
||
|
|
||
|
// Calculate new size and check minimum
|
||
|
int length = getSmallerSize(array.length);
|
||
|
//System.out.println("reduce from "+array.length+" to "+length);
|
||
|
initializeMap(length);
|
||
|
|
||
|
// Re-hash old data
|
||
|
for (List<Pair<K, V>> list : temp) {
|
||
|
for (Pair<K, V> p :list) {
|
||
|
this.put(p);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Increases the input ten-fold. e.g. 16->160
|
||
|
*/
|
||
|
private static final int getLargerSize(int input) {
|
||
|
return input*10;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns one fourth of the input. e.g. 16->4
|
||
|
*/
|
||
|
private static final int getSmallerSize(int input) {
|
||
|
return input/4;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Initialize the hash array.
|
||
|
*/
|
||
|
private void initializeMap(int length) {
|
||
|
this.array = new ArrayList[length];
|
||
|
for (int i = 0; i < array.length; i++)
|
||
|
this.array[i] = new ArrayList<Pair<K, V>>(initialListSize);
|
||
|
this.size = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts the key into an integer.
|
||
|
*
|
||
|
* @param h
|
||
|
* hash to get index of.
|
||
|
* @param length
|
||
|
* length of array
|
||
|
*
|
||
|
* @return Integer which represents the key.
|
||
|
*/
|
||
|
private int indexOf(int h) {
|
||
|
return h & (array.length-1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public java.util.Map<K,V> toMap() {
|
||
|
return (new JavaCompatibleHashMap<K,V>(this));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean validate() {
|
||
|
java.util.Set<K> keys = new java.util.HashSet<K>();
|
||
|
for (List<Pair<K, V>> list : array) {
|
||
|
for (Pair<K, V> pair : list) {
|
||
|
K k = pair.key;
|
||
|
V v = pair.value;
|
||
|
if (k==null || v==null) return false;
|
||
|
if (keys.contains(k)) return false;
|
||
|
keys.add(k);
|
||
|
}
|
||
|
}
|
||
|
return (keys.size()==size());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
StringBuilder builder = new StringBuilder();
|
||
|
for (int key = 0; key < array.length; key++) {
|
||
|
List<Pair<K, V>> list = array[key];
|
||
|
for (int item = 0; item < list.size(); item++) {
|
||
|
Pair<K, V> p = list.get(item);
|
||
|
V value = p.value;
|
||
|
if (value != null) builder.append(key).append("=").append(value).append(", ");
|
||
|
}
|
||
|
}
|
||
|
return builder.toString();
|
||
|
}
|
||
|
|
||
|
private static class JavaCompatibleHashMap<K,V> extends java.util.AbstractMap<K,V> {
|
||
|
|
||
|
private ChainingHashMap<K,V> map = null;
|
||
|
|
||
|
protected JavaCompatibleHashMap(ChainingHashMap<K,V> map) {
|
||
|
this.map = map;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V put(K key, V value) {
|
||
|
return map.put(key, value);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V remove(Object key) {
|
||
|
return map.remove((K)key);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean containsKey(Object key) {
|
||
|
return map.contains((K)key);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public void clear() {
|
||
|
map.clear();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public int size() {
|
||
|
return map.size();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public java.util.Set<java.util.Map.Entry<K, V>> entrySet() {
|
||
|
java.util.Set<java.util.Map.Entry<K, V>> set = new java.util.HashSet<java.util.Map.Entry<K, V>>() {
|
||
|
|
||
|
private static final long serialVersionUID = 1L;
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public java.util.Iterator<java.util.Map.Entry<K, V>> iterator() {
|
||
|
return (new JavaCompatibleIteratorWrapper<K,V>(map,super.iterator()));
|
||
|
}
|
||
|
};
|
||
|
for (List<Pair<K, V>> list : map.array) {
|
||
|
for (Pair<K, V> p : list) {
|
||
|
java.util.Map.Entry<K, V> entry = new JavaCompatibleMapEntry<K, V>(p.key, p.value);
|
||
|
set.add(entry);
|
||
|
}
|
||
|
}
|
||
|
return set;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class ProbingHashMap<K, V> extends HashMap<K, V> {
|
||
|
|
||
|
private int hashingKey = -1;
|
||
|
private float loadFactor = 0.6f;
|
||
|
private int minimumSize = 1024;
|
||
|
private Pair<K, V>[] array = null;
|
||
|
private int size = 0;
|
||
|
|
||
|
/**
|
||
|
* Create a hash map with K as the hash.
|
||
|
*
|
||
|
* @param size
|
||
|
* to use for the hash.
|
||
|
*/
|
||
|
public ProbingHashMap(int size) {
|
||
|
initializeMap(size);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a hash map with the default hashing key.
|
||
|
*/
|
||
|
public ProbingHashMap() {
|
||
|
initializeMap(minimumSize);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V put(K key, V value) {
|
||
|
return put(new Pair<K,V>(key,value));
|
||
|
}
|
||
|
|
||
|
private V put(Pair<K,V> newPair) {
|
||
|
V prev = null;
|
||
|
int index = indexOf(newPair.key);
|
||
|
|
||
|
// Check initial position
|
||
|
Pair<K, V> pair = array[index];
|
||
|
if (pair == null) {
|
||
|
array[index] = newPair;
|
||
|
size++;
|
||
|
|
||
|
// If size is greater than threshold
|
||
|
int maxSize = (int)(loadFactor*array.length);
|
||
|
if (size >= maxSize)
|
||
|
increase();
|
||
|
|
||
|
return prev;
|
||
|
}
|
||
|
|
||
|
if (pair.key.equals(newPair.key)) {
|
||
|
prev = pair.value;
|
||
|
pair.value = newPair.value;
|
||
|
return prev;
|
||
|
}
|
||
|
|
||
|
// Probing until we get back to the starting index
|
||
|
int start = getNextIndex(index);
|
||
|
while (start != index) {
|
||
|
pair = array[start];
|
||
|
if (pair == null) {
|
||
|
array[start] = newPair;
|
||
|
size++;
|
||
|
|
||
|
// If size is greater than threshold
|
||
|
int maxSize = (int)(loadFactor*array.length);
|
||
|
if (size >= maxSize)
|
||
|
increase();
|
||
|
|
||
|
return prev;
|
||
|
}
|
||
|
|
||
|
if (pair.key.equals(newPair.key)) {
|
||
|
prev = pair.value;
|
||
|
pair.value = newPair.value;
|
||
|
return prev;
|
||
|
}
|
||
|
|
||
|
start = getNextIndex(start);
|
||
|
}
|
||
|
// We should never get here.
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V get(K key) {
|
||
|
int index = indexOf(key);
|
||
|
Pair<K, V> pair = array[index];
|
||
|
|
||
|
// Check initial position
|
||
|
if (pair == null)
|
||
|
return null;
|
||
|
if (pair.key.equals(key))
|
||
|
return pair.value;
|
||
|
|
||
|
// Probing until we get back to the starting index
|
||
|
int start = getNextIndex(index);
|
||
|
while (start != index) {
|
||
|
pair = array[start];
|
||
|
|
||
|
if (pair == null)
|
||
|
return null;
|
||
|
if (pair.key.equals(key))
|
||
|
return pair.value;
|
||
|
|
||
|
start = getNextIndex(start);
|
||
|
}
|
||
|
// If we get here, probing failed.
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean contains(K key) {
|
||
|
return (get(key)!=null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V remove(K key) {
|
||
|
int index = indexOf(key);
|
||
|
Pair<K, V> prev = null;
|
||
|
|
||
|
// Check initial position
|
||
|
Pair<K, V> pair = array[index];
|
||
|
if (pair != null && pair.key.equals(key)) {
|
||
|
prev = array[index];
|
||
|
array[index] = null;
|
||
|
size--;
|
||
|
|
||
|
int loadFactored = (int)(size/loadFactor);
|
||
|
int smallerSize = getSmallerSize(array.length);
|
||
|
if (loadFactored < smallerSize && smallerSize > minimumSize)
|
||
|
reduce();
|
||
|
|
||
|
return prev.value;
|
||
|
}
|
||
|
|
||
|
// Probing until we get back to the starting index
|
||
|
int start = getNextIndex(index);
|
||
|
while (start != index) {
|
||
|
pair = array[start];
|
||
|
if (pair != null && pair.key.equals(key)) {
|
||
|
prev = array[start];
|
||
|
array[start] = null;
|
||
|
size--;
|
||
|
|
||
|
int loadFactored = (int)(size/loadFactor);
|
||
|
int smallerSize = getSmallerSize(array.length);
|
||
|
if (loadFactored < smallerSize && smallerSize > minimumSize)
|
||
|
reduce();
|
||
|
|
||
|
return prev.value;
|
||
|
}
|
||
|
start = getNextIndex(start);
|
||
|
}
|
||
|
// If we get here, probing failed.
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public void clear() {
|
||
|
for (int i=0; i<array.length; i++)
|
||
|
array = null;
|
||
|
size = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public int size() {
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
private void initializeMap(int current) {
|
||
|
int length = getLargerSize(current);
|
||
|
array = new Pair[length];
|
||
|
size = 0;
|
||
|
hashingKey = length;
|
||
|
}
|
||
|
|
||
|
private void increase() {
|
||
|
// Save old data
|
||
|
Pair<K,V>[] temp = this.array;
|
||
|
|
||
|
// Calculate new size and assign
|
||
|
int length = getLargerSize(array.length);
|
||
|
//System.out.println("increase from "+array.length+" to "+length);
|
||
|
initializeMap(length);
|
||
|
|
||
|
// Re-hash old data
|
||
|
for (Pair<K,V> p : temp) {
|
||
|
if (p != null)
|
||
|
this.put(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void reduce() {
|
||
|
// Save old data
|
||
|
Pair<K,V>[] temp = this.array;
|
||
|
|
||
|
// Calculate new size and check minimum
|
||
|
int length = getSmallerSize(array.length);
|
||
|
//System.out.println("reduce from "+array.length+" to "+length);
|
||
|
initializeMap(length);
|
||
|
|
||
|
// Re-hash old data
|
||
|
for (Pair<K,V> p : temp) {
|
||
|
if (p != null)
|
||
|
this.put(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Doubles the input. e.g. 16->32
|
||
|
*/
|
||
|
private static final int getLargerSize(int input) {
|
||
|
return input<<1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns one fourth of the input. e.g. 16->8->4
|
||
|
*/
|
||
|
private static final int getSmallerSize(int input) {
|
||
|
return input>>1>>1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the next index in the probing sequence, at this point it's linear
|
||
|
*/
|
||
|
private int getNextIndex(int input) {
|
||
|
int i = input+1;
|
||
|
if (i >= array.length)
|
||
|
i = 0;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The hashing function. Converts the key into an integer.
|
||
|
*
|
||
|
* @param key
|
||
|
* to create a hash for.
|
||
|
* @return Integer which represents the key.
|
||
|
*/
|
||
|
private int indexOf(K key) {
|
||
|
int k = key.hashCode() % hashingKey;
|
||
|
if (k>=array.length)
|
||
|
k = k - ((k/array.length) * array.length);
|
||
|
return k;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public java.util.Map<K,V> toMap() {
|
||
|
return (new JavaCompatibleHashMap<K,V>(this));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean validate() {
|
||
|
java.util.Set<K> keys = new java.util.HashSet<K>();
|
||
|
for (Pair<K, V> pair : array) {
|
||
|
if (pair == null)
|
||
|
continue;
|
||
|
|
||
|
K k = pair.key;
|
||
|
V v = pair.value;
|
||
|
if (k==null || v==null)
|
||
|
return false;
|
||
|
if (keys.contains(k))
|
||
|
return false;
|
||
|
keys.add(k);
|
||
|
}
|
||
|
return (keys.size()==size());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
StringBuilder builder = new StringBuilder();
|
||
|
for (int key = 0; key < array.length; key++) {
|
||
|
Pair<K, V> p = array[key];
|
||
|
if (p == null)
|
||
|
continue;
|
||
|
V value = p.value;
|
||
|
if (value != null)
|
||
|
builder.append(key).append("=").append(value).append(", ");
|
||
|
}
|
||
|
return builder.toString();
|
||
|
}
|
||
|
|
||
|
private static class JavaCompatibleHashMap<K,V> extends java.util.AbstractMap<K,V> {
|
||
|
|
||
|
private ProbingHashMap<K,V> map = null;
|
||
|
|
||
|
protected JavaCompatibleHashMap(ProbingHashMap<K,V> map) {
|
||
|
this.map = map;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V put(K key, V value) {
|
||
|
return map.put(key, value);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V remove(Object key) {
|
||
|
return map.remove((K)key);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean containsKey(Object key) {
|
||
|
return map.contains((K)key);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public void clear() {
|
||
|
map.clear();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public int size() {
|
||
|
return map.size();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public java.util.Set<java.util.Map.Entry<K, V>> entrySet() {
|
||
|
java.util.Set<java.util.Map.Entry<K, V>> set = new java.util.HashSet<java.util.Map.Entry<K, V>>() {
|
||
|
|
||
|
private static final long serialVersionUID = 1L;
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public java.util.Iterator<java.util.Map.Entry<K, V>> iterator() {
|
||
|
return (new JavaCompatibleIteratorWrapper<K,V>(map,super.iterator()));
|
||
|
}
|
||
|
};
|
||
|
for (Pair<K, V> p : map.array) {
|
||
|
if (p==null)
|
||
|
continue;
|
||
|
java.util.Map.Entry<K, V> entry = new JavaCompatibleMapEntry<K, V>(p.key, p.value);
|
||
|
set.add(entry);
|
||
|
}
|
||
|
return set;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a hash map with K as the hashing key.
|
||
|
*
|
||
|
* @param type
|
||
|
* type of hashing to use.
|
||
|
* @param size
|
||
|
* initialize size.
|
||
|
*/
|
||
|
public HashMap(Type type, int size) {
|
||
|
if (type == Type.CHAINING) {
|
||
|
delegateMap = new ChainingHashMap<K,V>(size);
|
||
|
} else if (type == Type.PROBING) {
|
||
|
delegateMap = new ProbingHashMap<K,V>(size);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a hash map with the default hashing key.
|
||
|
*
|
||
|
* @param type
|
||
|
* type of hashing to use.
|
||
|
*/
|
||
|
public HashMap(Type type) {
|
||
|
if (type == Type.CHAINING) {
|
||
|
delegateMap = new ChainingHashMap<K,V>();
|
||
|
} else if (type == Type.PROBING) {
|
||
|
delegateMap = new ProbingHashMap<K,V>();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private HashMap() { }
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V put(K key, V value) {
|
||
|
return delegateMap.put(key, value);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V get(K key) {
|
||
|
return delegateMap.get(key);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean contains(K key) {
|
||
|
return (get(key)!=null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public V remove(K key) {
|
||
|
return delegateMap.remove(key);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public void clear() {
|
||
|
delegateMap.clear();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public int size() {
|
||
|
return delegateMap.size();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public java.util.Map<K,V> toMap() {
|
||
|
return delegateMap.toMap();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean validate() {
|
||
|
return delegateMap.validate();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
return delegateMap.toString();
|
||
|
}
|
||
|
|
||
|
private static final class Pair<K, V> {
|
||
|
|
||
|
private K key = null;
|
||
|
private V value = null;
|
||
|
|
||
|
public Pair(K key, V value) {
|
||
|
this.key = key;
|
||
|
this.value = value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
return 31 * (this.key.hashCode());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean equals(Object obj) {
|
||
|
if (obj == null)
|
||
|
return false;
|
||
|
if (!(obj instanceof Pair))
|
||
|
return false;
|
||
|
|
||
|
Pair<K, V> pair = (Pair<K, V>) obj;
|
||
|
return key.equals(pair.key);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class JavaCompatibleIteratorWrapper<K,V> implements java.util.Iterator<java.util.Map.Entry<K, V>> {
|
||
|
|
||
|
private HashMap<K,V> map = null;
|
||
|
private java.util.Iterator<java.util.Map.Entry<K, V>> iter = null;
|
||
|
private java.util.Map.Entry<K, V> lastEntry = null;
|
||
|
|
||
|
public JavaCompatibleIteratorWrapper(HashMap<K,V> map, java.util.Iterator<java.util.Map.Entry<K, V>> iter) {
|
||
|
this.map = map;
|
||
|
this.iter = iter;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean hasNext() {
|
||
|
if (iter==null)
|
||
|
return false;
|
||
|
return iter.hasNext();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public java.util.Map.Entry<K, V> next() {
|
||
|
if (iter==null)
|
||
|
return null;
|
||
|
|
||
|
lastEntry = iter.next();
|
||
|
return lastEntry;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
@Override
|
||
|
public void remove() {
|
||
|
if (iter==null || lastEntry==null)
|
||
|
return;
|
||
|
|
||
|
map.remove(lastEntry.getKey());
|
||
|
iter.remove();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class JavaCompatibleMapEntry<K,V> extends java.util.AbstractMap.SimpleEntry<K,V> {
|
||
|
|
||
|
private static final long serialVersionUID = 3282082818647198608L;
|
||
|
|
||
|
public JavaCompatibleMapEntry(K key, V value) {
|
||
|
super(key, value);
|
||
|
}
|
||
|
}
|
||
|
}
|