Add generic hashmaps (#3195)

This commit is contained in:
Divya Raichura
2022-07-18 01:30:55 +05:30
committed by GitHub
parent 1a9937c7cb
commit ffd02504d9
4 changed files with 335 additions and 0 deletions

View File

@ -0,0 +1,125 @@
package com.thealgorithms.datastructures.hashmap.hashing;
import java.util.LinkedList;
// implementation of generic hashmaps using array of Linked Lists
public class GenericHashMapUsingArray<K, V> {
private int size; // n (total number of key-value pairs)
private LinkedList<Node>[] buckets; // N = buckets.length
private float lf = 0.75f;
public GenericHashMapUsingArray() {
initBuckets(16);
size = 0;
}
// load factor = 0.75 means if we need to add 100 items and we have added
// 75, then adding 76th item it will double the size, copy all elements
// & then add 76th item.
private void initBuckets(int N) {
buckets = new LinkedList[N];
for (int i = 0; i < buckets.length; i++) {
buckets[i] = new LinkedList<>();
}
}
public void put(K key, V value) {
int bucketIndex = hashFunction(key);
LinkedList<Node> nodes = buckets[bucketIndex];
for (Node node : nodes) { // if key present => update
if (node.key.equals(key)) {
node.value = value;
return;
}
}
// key is not present => insert
nodes.add(new Node(key, value));
size++;
if ((float) size / buckets.length > lf) {
reHash();
}
}
// tells which bucket to go to
private int hashFunction(K key) {
int hc = key.hashCode();
return Math.abs(hc) % buckets.length;
}
private void reHash() {
System.out.println("Rehashing!");
LinkedList<Node>[] old = buckets;
initBuckets(old.length * 2);
this.size = 0;
for (LinkedList<Node> nodes : old) {
for (Node node : nodes) {
put(node.key, node.value);
}
}
}
public void remove(K key) {
int bucketIndex = hashFunction(key);
LinkedList<Node> nodes = buckets[bucketIndex];
Node target = null;
for (Node node : nodes) {
if (node.key.equals(key)) {
target = node;
break;
}
}
nodes.remove(target);
size--;
}
public int size() {
return this.size;
}
public V get(K key) {
int bucketIndex = hashFunction(key);
LinkedList<Node> nodes = buckets[bucketIndex];
for (Node node : nodes) {
if (node.key.equals(key)) {
return node.value;
}
}
return null;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("{");
for (LinkedList<Node> nodes : buckets) {
for (Node node : nodes) {
builder.append(node.key);
builder.append(" : ");
builder.append(node.value);
builder.append(", ");
}
}
builder.append("}");
return builder.toString();
}
public boolean containsKey(K key) {
return get(key) != null;
}
public class Node {
K key;
V value;
public Node(K key, V value) {
this.key = key;
this.value = value;
}
}
}

View File

@ -0,0 +1,112 @@
package com.thealgorithms.datastructures.hashmap.hashing;
import java.util.ArrayList;
import java.util.LinkedList;
public class GenericHashMapUsingArrayList<K, V> {
ArrayList<LinkedList<Node>> buckets;
private float lf = 0.5f;
private int size;
public GenericHashMapUsingArrayList() {
buckets = new ArrayList<>();
for (int i = 0; i < 10; i++) {
buckets.add(new LinkedList<>());
}
size = 0;
}
public void put(K key, V value) {
int hash = Math.abs(key.hashCode() % buckets.size());
LinkedList<Node> nodes = buckets.get(hash);
for (Node node : nodes) {
if (node.key.equals(key)) {
node.val = value;
return;
}
}
nodes.add(new Node(key, value));
size++;
if ((float) size / buckets.size() > lf) {
reHash();
}
}
private void reHash() {
ArrayList<LinkedList<Node>> old = buckets;
buckets = new ArrayList<>();
size = 0;
for (int i = 0; i < old.size() * 2; i++) {
buckets.add(new LinkedList<>());
}
for (LinkedList<Node> nodes : buckets) {
for (Node node : nodes) {
put(node.key, node.val);
}
}
}
public V get(K key) {
int hash = Math.abs(key.hashCode() % buckets.size());
LinkedList<Node> nodes = buckets.get(hash);
for (Node node : nodes) {
if (node.key.equals(key)) {
return node.val;
}
}
return null;
}
public void remove(K key) {
int hash = Math.abs(key.hashCode() % buckets.size());
LinkedList<Node> nodes = buckets.get(hash);
Node target = null;
for (Node node : nodes) {
if (node.key.equals(key)) {
target = node;
break;
}
}
nodes.remove(target);
size--;
}
public boolean containsKey(K key) {
return get(key) != null;
}
public int size() {
return this.size;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("{");
for (LinkedList<Node> nodes : buckets) {
for (Node node : nodes) {
builder.append(node.key);
builder.append(" : ");
builder.append(node.val);
builder.append(", ");
}
}
builder.append("}");
return builder.toString();
}
private class Node {
K key;
V val;
public Node(K key, V val) {
this.key = key;
this.val = val;
}
}
}

View File

@ -0,0 +1,49 @@
package com.thealgorithms.datastructures.hashmap.hashing;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class GenericHashMapUsingArrayListTest {
@Test
void testGenericHashmapWhichUsesArrayAndBothKeyAndValueAreStrings() {
GenericHashMapUsingArrayList<String, String> map = new GenericHashMapUsingArrayList<>();
map.put("USA", "Washington DC");
map.put("Nepal", "Kathmandu");
map.put("India", "New Delhi");
map.put("Australia", "Sydney");
assertNotNull(map);
assertEquals(4, map.size());
assertEquals("Kathmandu", map.get("Nepal"));
assertEquals("Sydney", map.get("Australia"));
}
@Test
void testGenericHashmapWhichUsesArrayAndKeyIsStringValueIsInteger() {
GenericHashMapUsingArrayList<String, Integer> map = new GenericHashMapUsingArrayList<>();
map.put("USA", 87);
map.put("Nepal", 25);
map.put("India", 101);
map.put("Australia", 99);
assertNotNull(map);
assertEquals(4, map.size());
assertEquals(25, map.get("Nepal"));
assertEquals(99, map.get("Australia"));
map.remove("Nepal");
assertFalse(map.containsKey("Nepal"));
}
@Test
void testGenericHashmapWhichUsesArrayAndKeyIsIntegerValueIsString() {
GenericHashMapUsingArrayList<Integer, String> map = new GenericHashMapUsingArrayList<>();
map.put(101, "Washington DC");
map.put(34, "Kathmandu");
map.put(46, "New Delhi");
map.put(89, "Sydney");
assertNotNull(map);
assertEquals(4, map.size());
assertEquals("Sydney", map.get(89));
assertEquals("Washington DC", map.get(101));
assertTrue(map.containsKey(46));
}
}

View File

@ -0,0 +1,49 @@
package com.thealgorithms.datastructures.hashmap.hashing;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class GenericHashMapUsingArrayTest {
@Test
void testGenericHashmapWhichUsesArrayAndBothKeyAndValueAreStrings() {
GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
map.put("USA", "Washington DC");
map.put("Nepal", "Kathmandu");
map.put("India", "New Delhi");
map.put("Australia", "Sydney");
assertNotNull(map);
assertEquals(4, map.size());
assertEquals("Kathmandu", map.get("Nepal"));
assertEquals("Sydney", map.get("Australia"));
}
@Test
void testGenericHashmapWhichUsesArrayAndKeyIsStringValueIsInteger() {
GenericHashMapUsingArray<String, Integer> map = new GenericHashMapUsingArray<>();
map.put("USA", 87);
map.put("Nepal", 25);
map.put("India", 101);
map.put("Australia", 99);
assertNotNull(map);
assertEquals(4, map.size());
assertEquals(25, map.get("Nepal"));
assertEquals(99, map.get("Australia"));
map.remove("Nepal");
assertFalse(map.containsKey("Nepal"));
}
@Test
void testGenericHashmapWhichUsesArrayAndKeyIsIntegerValueIsString() {
GenericHashMapUsingArray<Integer, String> map = new GenericHashMapUsingArray<>();
map.put(101, "Washington DC");
map.put(34, "Kathmandu");
map.put(46, "New Delhi");
map.put(89, "Sydney");
assertNotNull(map);
assertEquals(4, map.size());
assertEquals("Sydney", map.get(89));
assertEquals("Washington DC", map.get(101));
assertTrue(map.containsKey(46));
}
}