diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java
index a1ef457f3..89e25f4eb 100644
--- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java
+++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java
@@ -3,12 +3,34 @@ package com.thealgorithms.datastructures.hashmap.hashing;
import java.util.ArrayList;
import java.util.LinkedList;
+/**
+ * A generic implementation of a hash map using an array list of linked lists for collision resolution.
+ * This class allows storage of key-value pairs with average-case constant time complexity for insertion,
+ * deletion, and retrieval operations.
+ *
+ *
+ * The hash map uses separate chaining to handle collisions. Each bucket in the hash map is represented
+ * by a linked list that holds nodes containing key-value pairs. When multiple keys hash to the same index,
+ * they are stored in the same linked list.
+ *
+ *
+ *
+ * The hash map automatically resizes itself when the load factor exceeds 0.5. The load factor is defined
+ * as the ratio of the number of entries to the number of buckets. When resizing occurs, all existing entries
+ * are rehashed and inserted into the new buckets.
+ *
+ *
+ * @param the type of keys maintained by this hash map
+ * @param the type of mapped values
+ */
public class GenericHashMapUsingArrayList {
- ArrayList> buckets;
- private float lf = 0.5f;
- private int size;
+ private ArrayList> buckets; // Array list of buckets (linked lists)
+ private int size; // Number of key-value pairs in the hash map
+ /**
+ * Constructs a new empty hash map with an initial capacity of 10 buckets.
+ */
public GenericHashMapUsingArrayList() {
buckets = new ArrayList<>();
for (int i = 0; i < 10; i++) {
@@ -17,6 +39,13 @@ public class GenericHashMapUsingArrayList {
size = 0;
}
+ /**
+ * Associates the specified value with the specified key in this map.
+ * If the map previously contained a mapping for the key, the old value is replaced.
+ *
+ * @param key the key with which the specified value is to be associated
+ * @param value the value to be associated with the specified key
+ */
public void put(K key, V value) {
int hash = Math.abs(key.hashCode() % buckets.size());
LinkedList nodes = buckets.get(hash);
@@ -31,25 +60,36 @@ public class GenericHashMapUsingArrayList {
nodes.add(new Node(key, value));
size++;
- if ((float) size / buckets.size() > lf) {
+ // Load factor threshold for resizing
+ float loadFactorThreshold = 0.5f;
+ if ((float) size / buckets.size() > loadFactorThreshold) {
reHash();
}
}
+ /**
+ * Resizes the hash map by doubling the number of buckets and rehashing existing entries.
+ */
private void reHash() {
- ArrayList> old = buckets;
+ ArrayList> oldBuckets = buckets;
buckets = new ArrayList<>();
size = 0;
- for (int i = 0; i < old.size() * 2; i++) {
+ for (int i = 0; i < oldBuckets.size() * 2; i++) {
buckets.add(new LinkedList<>());
}
- for (LinkedList nodes : buckets) {
+ for (LinkedList nodes : oldBuckets) {
for (Node node : nodes) {
put(node.key, node.val);
}
}
}
+ /**
+ * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
+ *
+ * @param key the key whose associated value is to be returned
+ * @return the value associated with the specified key, or null if no mapping exists
+ */
public V get(K key) {
int hash = Math.abs(key.hashCode() % buckets.size());
LinkedList nodes = buckets.get(hash);
@@ -61,6 +101,11 @@ public class GenericHashMapUsingArrayList {
return null;
}
+ /**
+ * Removes the mapping for the specified key from this map if present.
+ *
+ * @param key the key whose mapping is to be removed from the map
+ */
public void remove(K key) {
int hash = Math.abs(key.hashCode() % buckets.size());
LinkedList nodes = buckets.get(hash);
@@ -72,18 +117,36 @@ public class GenericHashMapUsingArrayList {
break;
}
}
- nodes.remove(target);
- size--;
+ if (target != null) {
+ nodes.remove(target);
+ size--;
+ }
}
+ /**
+ * Returns true if this map contains a mapping for the specified key.
+ *
+ * @param key the key whose presence in this map is to be tested
+ * @return true if this map contains a mapping for the specified key
+ */
public boolean containsKey(K key) {
return get(key) != null;
}
+ /**
+ * Returns the number of key-value pairs in this map.
+ *
+ * @return the number of key-value pairs
+ */
public int size() {
return this.size;
}
+ /**
+ * Returns a string representation of the map, containing all key-value pairs.
+ *
+ * @return a string representation of the map
+ */
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
@@ -96,15 +159,27 @@ public class GenericHashMapUsingArrayList {
builder.append(", ");
}
}
+ // Remove trailing comma and space if there are any elements
+ if (builder.length() > 1) {
+ builder.setLength(builder.length() - 2);
+ }
builder.append("}");
return builder.toString();
}
+ /**
+ * A private inner class representing a key-value pair (node) in the hash map.
+ */
private class Node {
-
K key;
V val;
+ /**
+ * Constructs a new Node with the specified key and value.
+ *
+ * @param key the key of the key-value pair
+ * @param val the value of the key-value pair
+ */
Node(K key, V val) {
this.key = key;
this.val = val;
diff --git a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java
index 37e43d2aa..629aaae95 100644
--- a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java
@@ -50,4 +50,47 @@ class GenericHashMapUsingArrayListTest {
assertEquals("Washington DC", map.get(101));
assertTrue(map.containsKey(46));
}
+
+ @Test
+ void testRemoveNonExistentKey() {
+ GenericHashMapUsingArrayList map = new GenericHashMapUsingArrayList<>();
+ map.put("USA", "Washington DC");
+ map.remove("Nepal"); // Attempting to remove a non-existent key
+ assertEquals(1, map.size()); // Size should remain the same
+ }
+
+ @Test
+ void testRehashing() {
+ GenericHashMapUsingArrayList map = new GenericHashMapUsingArrayList<>();
+ for (int i = 0; i < 20; i++) {
+ map.put("Key" + i, "Value" + i);
+ }
+ assertEquals(20, map.size()); // Ensure all items were added
+ assertEquals("Value5", map.get("Key5")); // Check retrieval after rehash
+ }
+
+ @Test
+ void testUpdateValueForExistingKey() {
+ GenericHashMapUsingArrayList map = new GenericHashMapUsingArrayList<>();
+ map.put("USA", "Washington DC");
+ map.put("USA", "New Washington DC"); // Updating value for existing key
+ assertEquals("New Washington DC", map.get("USA"));
+ }
+
+ @Test
+ void testToStringMethod() {
+ GenericHashMapUsingArrayList map = new GenericHashMapUsingArrayList<>();
+ map.put("USA", "Washington DC");
+ map.put("Nepal", "Kathmandu");
+ String expected = "{USA : Washington DC, Nepal : Kathmandu}";
+ assertEquals(expected, map.toString());
+ }
+
+ @Test
+ void testContainsKey() {
+ GenericHashMapUsingArrayList map = new GenericHashMapUsingArrayList<>();
+ map.put("USA", "Washington DC");
+ assertTrue(map.containsKey("USA"));
+ assertFalse(map.containsKey("Nepal"));
+ }
}