Adds open addressing linked hash table

master
Abhinav Sarkar 2019-06-27 22:43:18 +05:30
parent a75f826e1b
commit ba1023bca1
3 changed files with 264 additions and 2 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.idea
*.iml
target/

View File

@ -21,7 +21,7 @@ public class ChainingHashTable<K, V>
return Optional.empty();
} else {
return entries.forEach(h -> {
if (h.key == key) {
if (h.key.equals(key)) {
return Optional.of(h.val);
}
return Optional.empty();
@ -38,7 +38,7 @@ public class ChainingHashTable<K, V>
} else {
LinkedList<Entry<K, V>> entries = (LinkedList<Entry<K, V>>) store[index];
Optional<Integer> ret = entries.forEach(h -> {
if (h.key == key)
if (h.key.equals(key))
{
h.val = val;
return Optional.of(0);

View File

@ -0,0 +1,261 @@
package net.abhinavsarkar.algorist;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Optional;
public class OpenAddressingHashTable<K, V> implements Iterable<OpenAddressingHashTable.Entry<K, V>>
{
private static final Entry REMOVED = new Entry(0,0);
private Object[] store;
private ProbingStrategy probingStrategy;
private Entry<K, V> head;
private Entry<K, V> tail;
public OpenAddressingHashTable(int initialCapacity, ProbingStrategy probingStrategy) {
this.store = new Object[initialCapacity];
this.probingStrategy = probingStrategy;
}
public Optional<V> get(K key) {
int trial = 0;
int baseIndex = calcIndex(key, store.length);
int firstRemovedIndex = -1;
while (trial < store.length)
{
int index = probingStrategy.nextIndex(baseIndex, trial, store.length);
Entry<K,V> entry = (Entry<K,V>) store[index];
if (entry == null)
{
return Optional.empty();
}
else if (entry == REMOVED && firstRemovedIndex == -1) {
firstRemovedIndex = index;
}
else if (entry.key.equals(key))
{
if (firstRemovedIndex != -1) {
store[firstRemovedIndex] = entry;
store[index] = REMOVED;
}
return Optional.of(entry.val);
}
trial++;
}
return Optional.empty();
}
public void put(K key, V val) {
if (!doPut(new Entry<>(key, val), store, false)) {
resize();
put(key, val);
}
}
private void resize() {
Object[] nStore = new Object[store.length * 2];
for (Entry<K, V> entry : this)
{
if (!doPut(entry, nStore, true))
{
throw new IllegalStateException("Something is wrong");
}
}
this.store = nStore;
}
private boolean doPut(Entry<K,V> nEntry, Object[] store, boolean resize) {
int trial = 0;
int baseIndex = calcIndex(nEntry.key, store.length);
while (trial < store.length) {
int index = probingStrategy.nextIndex(baseIndex, trial, store.length);
Entry<K,V> entry = (Entry<K,V>) store[index];
if (entry == null || entry == REMOVED)
{
if (!resize)
{
addLink(nEntry);
}
store[index] = nEntry;
return true;
}
else if (entry.key.equals(nEntry.key))
{
entry.val = nEntry.val;
return true;
}
trial++;
}
return false;
}
private void addLink(Entry<K, V> nEntry)
{
if (head == null)
{
head = nEntry;
}
else
{
tail.next = nEntry;
nEntry.prev = tail;
}
tail = nEntry;
}
public void remove(K key) {
int trial = 0;
int baseIndex = calcIndex(key, store.length);
while (trial < store.length)
{
int index = probingStrategy.nextIndex(baseIndex, trial, store.length);
Entry<K,V> entry = (Entry<K,V>) store[index];
if (entry == null)
{
return;
}
else if (entry.key.equals(key))
{
removeLink(entry);
store[index] = REMOVED;
return;
}
trial++;
}
}
private void removeLink(Entry<K, V> entry)
{
if (head == entry) {
head = entry.next;
}
if (tail == entry) {
tail = entry.prev;
}
if (entry.prev != null) {
entry.prev.next = entry.next;
}
if (entry.next != null) {
entry.next.prev = entry.prev;
}
}
private int calcIndex(K key, int size) {
return key.hashCode() % size;
}
public Iterator<Entry<K,V>> iterator() {
return new LinkedHashTableIterator();
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (Entry<K,V> entry : this)
{
sb.append(entry + ", ");
}
sb.delete(sb.length()-2, sb.length());
return "{" + sb + "}";
}
public interface ProbingStrategy {
int nextIndex(int baseIndex, int probingTrial, int size);
}
public static class LinearProbing implements ProbingStrategy {
public int nextIndex(int baseIndex, int probingTrial, int size) {
return (baseIndex + probingTrial) % size;
}
}
public static class QuadraticProbing implements ProbingStrategy {
public int nextIndex(int baseIndex, int probingTrial, int size) {
return (baseIndex + probingTrial * probingTrial) % size;
}
}
public static class Entry<K, V> {
private K key;
private V val;
private Entry<K, V> prev;
private Entry<K, V> next;
public Entry(K key, V val) {
this.key = key;
this.val = val;
}
public String toString() {
return "<" + key + "," + val + ">";
}
}
private class HashTableIterator implements Iterator<Entry<K,V>> {
private int index = 0;
private int size = store.length;
public boolean hasNext() {
return index < size;
}
public Entry<K,V> next() {
while (index < size) {
Entry<K,V> entry = (Entry<K,V>) store[index++];
if (entry != null && entry != REMOVED) {
return entry;
}
}
throw new NoSuchElementException();
}
}
private class LinkedHashTableIterator implements Iterator<Entry<K,V>> {
private Entry<K,V> start = head;
public boolean hasNext() {
return start != null;
}
public Entry<K,V> next() {
if (start != null) {
Entry<K, V> entry = start;
start = start.next;
return entry;
}
throw new NoSuchElementException();
}
}
public static void main(String[] args)
{
OpenAddressingHashTable<String, String> table =
new OpenAddressingHashTable<>(4, new LinearProbing());
table.put("a", "abhinav");
table.put("b", "batman");
table.put("c", "carol");
table.put("c", "carly");
table.put("z", "zellman");
table.put("w", "walker");
System.out.println(table);
table.remove("x");
table.remove("z");
System.out.println(table.get("a"));
System.out.println(table.get("b"));
System.out.println(table.get("c"));
System.out.println(table.get("w"));
System.out.println(table.get("z"));
table.put("z", "zebra");
System.out.println(table.get("z"));
System.out.println(table);
System.out.println(table.get("A"));
System.out.println(table.get("B"));
System.out.println(table.get("C"));
}
}