Skip to content

Instantly share code, notes, and snippets.

@ambud
Created January 2, 2016 18:55
Show Gist options
  • Save ambud/e05fd948ec69062156d1 to your computer and use it in GitHub Desktop.
Save ambud/e05fd948ec69062156d1 to your computer and use it in GitHub Desktop.
An efficient reusable Hashmap (concept ref: http://www.algolist.net/Data_structures/Hash_table/Simple_example)
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
public class ReusableHashMap<K, V> implements Map<K, V> {
private int size;
private ReusableEntry<K, V>[] entries;
public ReusableHashMap() {
this(16);
}
@SuppressWarnings("unchecked")
public ReusableHashMap(int capacity) {
entries = (ReusableEntry<K, V>[]) new ReusableEntry[capacity];
for (int i = 0; i < capacity; i++) {
entries[i] = new ReusableEntry<K, V>(null, null);
}
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean containsKey(Object key) {
int initialLocation = (key.hashCode() & 0x7fffffff) % entries.length;
int pointer = initialLocation;
do {
if (entries[pointer].isStale()) {
return false;
} else if (entries[pointer].key.equals(key)) {
return true;
} else {
if (pointer == entries.length - 1) {
// reset pointer
pointer = 0;
} else {
pointer++;
}
}
} while (pointer != initialLocation);
return false;
}
@Override
public boolean containsValue(Object value) {
return false;
}
@Override
public V get(Object key) {
int initialLocation = (key.hashCode() & 0x7fffffff) % entries.length;
int pointer = initialLocation;
do {
if (entries[pointer].isStale()) {
return null;
} else if (entries[pointer].key.equals(key)) {
return entries[pointer].value;
} else {
if (pointer == entries.length - 1) {
// reset pointer
pointer = 0;
} else {
pointer++;
}
}
} while (pointer != initialLocation);
return null;
}
@Override
public V put(K key, V value) {
if(size==entries.length) {
// short circuit if there's no capacity left to store this data
return null;
}
int initialLocation = (key.hashCode() & 0x7fffffff) % entries.length;
int pointer = initialLocation;
do {
if (entries[pointer].isStale()) {
entries[pointer].key = key;
entries[pointer].value = value;
entries[pointer].stale = false;
size++;
return null;
} else if (entries[pointer].key.equals(key)) {
V tmp = entries[pointer].value;
entries[pointer].value = value;
return tmp;
} else {
if (pointer == entries.length - 1) {
// reset pointer
pointer = 0;
} else {
pointer++;
}
}
} while (pointer != initialLocation);
return null;
}
@Override
public V remove(Object key) {
return null;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
// not supported yet
}
@Override
public void clear() {
for (int i = 0; i < entries.length; i++) {
ReusableEntry<K, V> reusableEntry = entries[i];
reusableEntry.stale = true;
}
}
@Override
public Set<K> keySet() {
// not supported yet
return null;
}
@Override
public Collection<V> values() {
// not supported yet
return null;
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
// not supported yet
return null;
}
@Override
public String toString() {
return Arrays.toString(entries);
}
public static class ReusableEntry<K, V> implements Entry<K, V> {
private boolean stale = true;
private K key;
private V value;
public ReusableEntry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
return value;
}
public boolean isStale() {
return stale;
}
public void setStale(boolean stale) {
this.stale = stale;
}
@Override
public String toString() {
return "[stale=" + stale + ", key=" + key + ", value=" + value + "]";
}
}
}
import java.util.HashMap;
import java.util.Map;
public class TestReusableHash {
public static void main(String[] args) {
int capacity = 30;
System.out.println("Testing hashmap");
Map<String, String> val = new HashMap<>(30);
for (int j = 0; j < 20; j++) {
long time = System.currentTimeMillis();
for (int k = 0; k < 1000000; k++) {
val.clear();
for (int i = 0; i < capacity; i++) {
val.put("hello" + i, "testing" + i);
}
}
System.out.println("Time:" + (System.currentTimeMillis() - time));
}
System.out.println("Testing reusable hashmap");
val = new ReusableHashMap<>(capacity);
for (int j = 0; j < 20; j++) {
long time = System.currentTimeMillis();
for (int k = 0; k < 1000000; k++) {
val.clear();
for (int i = 0; i < capacity; i++) {
val.put("hello" + i, "testing" + i);
}
}
System.out.println("Time:" + (System.currentTimeMillis() - time));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment