Created
January 2, 2016 18:55
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 + "]"; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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