org.psjava.ds.map.hashtable.OpenAddressingHashTable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of psjava Show documentation
Show all versions of psjava Show documentation
Problem Solving Library for Java
package org.psjava.ds.map.hashtable;
import java.util.Iterator;
import org.psjava.ds.map.MapEntry;
import org.psjava.ds.map.MutableMap;
import org.psjava.util.AssertStatus;
import org.psjava.util.ConvertedDataIterator;
import org.psjava.util.DataConverter;
import org.psjava.util.DataFilter;
import org.psjava.util.FilteredIterator;
import org.psjava.util.Java1DArray;
import org.psjava.util.VarargsIterator;
public class OpenAddressingHashTable implements MutableMap {
/**
* This is not very fast map. Because it's structure to provide flexibility of probing.
*/
private static class Entry implements MapEntry {
K keyOrNull; // if null then the entry is lazy deleted.
V value;
int keyHash;
Entry(K key, V value, int keyHash) {
this.keyOrNull = key;
this.value = value;
this.keyHash = keyHash;
}
@Override
public K getKey() {
AssertStatus.assertTrue(keyOrNull != null);
return keyOrNull;
}
@Override
public V getValue() {
AssertStatus.assertTrue(keyOrNull != null);
return value;
}
@Override
public String toString() {
if (keyOrNull == null)
return "";
return keyOrNull + "=" + value;
}
}
private static final int MAX_LOAD_FACTOR2 = 2;
private final HashProber prober;
protected Entry[] bucket;
protected int load = 0;
protected int lazyDeletedCount = 0;
public OpenAddressingHashTable(HashProber prober, int reserve) {
this.prober = prober;
bucket = Java1DArray.create(Entry.class, calcBucketSize(reserve));
}
protected static int calcBucketSize(int reserve) {
int size = 1;
while (size / MAX_LOAD_FACTOR2 < reserve)
size <<= 1;
return size;
}
@Override
public void clear() {
bucket = Java1DArray.create(Entry.class, calcBucketSize(1));
load = 0;
lazyDeletedCount = 0;
}
@Override
public void put(K key, V value) {
ensureArraysCapacity(load + 1);
putToCurrentArray(key, value);
}
protected void putToCurrentArray(final K key, final V value) {
final int keyHash = key.hashCode();
probe(keyHash, new BucketVisitor() {
@Override
public boolean visitAndGetContinuity(int pos) {
if (bucket[pos] != null) {
if (isKeyInBucket(pos, key, keyHash)) {
bucket[pos].keyOrNull = key;
bucket[pos].value = value;
return false;
} else {
return true;
}
} else {
bucket[pos] = new Entry(key, value, keyHash);
load++;
return false;
}
}
});
}
private void probe(int keyHash, BucketVisitor visitor) {
prober.probe(Math.abs(keyHash) % bucket.length, bucket.length, visitor);
}
protected void ensureArraysCapacity(int reserve) {
if (reserve <= bucket.length / MAX_LOAD_FACTOR2)
return;
Entry[] oldBucket = bucket;
bucket = Java1DArray.create(Entry.class, calcBucketSize(reserve));
load = 0;
lazyDeletedCount = 0;
for (Entry v : oldBucket)
if (v != null && v.keyOrNull != null)
putToCurrentArray(v.keyOrNull, v.value);
}
@Override
public V get(K key) {
Entry e = findEntry(key, null);
AssertStatus.assertTrue(e != null, "key is not in the map");
return e.value;
}
@Override
public V get(K key, V def) {
Entry e = findEntry(key, null);
if (e == null)
return def;
return e.value;
}
@Override
public boolean containsKey(K key) {
return findEntry(key, null) != null;
}
@Override
public void remove(final K key) {
Entry e = findEntry(key, null);
if (e != null) {
e.keyOrNull = null;
e.value = null;
lazyDeletedCount++;
}
}
@Override
public int size() {
return load - lazyDeletedCount;
}
private Entry findResult;
private Entry findEntry(final K key, Entry def) {
final int keyHash = key.hashCode();
findResult = def;
probe(keyHash, new BucketVisitor() {
@Override
public boolean visitAndGetContinuity(int pos) {
if (bucket[pos] != null) {
if (isKeyInBucket(pos, key, keyHash)) {
findResult = bucket[pos];
return false;
} else {
return true;
}
} else {
return false;
}
}
});
return findResult;
}
@Override
public Iterator> iterator() {
return ConvertedDataIterator.create(FilteredIterator.create(VarargsIterator.create(bucket), new DataFilter>() {
@Override
public boolean isAccepted(Entry v) {
return v != null && v.keyOrNull != null;
}
}), new DataConverter, MapEntry>() {
@Override
public MapEntry convert(Entry v) {
return v;
}
});
}
private boolean isKeyInBucket(int pos, K key, int keyHash) {
Entry e = bucket[pos];
return e.keyOrNull != null && e.keyHash == keyHash && e.keyOrNull.equals(key);
}
@Override
public boolean isEmpty() {
return load == 0;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy