From b8a502399e43da9d122e728041ceca3723786f27 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <hardikhpawar.cs21@rvce.edu.in>
Date: Thu, 24 Oct 2024 11:23:14 +0530
Subject: [PATCH 1/3] refactor: Enhance docs, add tests in
 `GenericHashMapUsingArray`

---
 .../hashing/GenericHashMapUsingArray.java     | 116 +++++++++++++++---
 .../hashing/GenericHashMapUsingArrayTest.java |  43 +++++++
 2 files changed, 139 insertions(+), 20 deletions(-)

diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
index 416cee99d028..5a05d8273f6b 100644
--- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
+++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
@@ -2,23 +2,46 @@
 
 import java.util.LinkedList;
 
-// implementation of generic hashmaps using array of Linked Lists
-
+/**
+ * A generic implementation of a hash map using an array of linked lists for collision resolution.
+ * This class provides a way to store key-value pairs efficiently, allowing for average-case
+ * constant time complexity for insertion, deletion, and retrieval operations.
+ *
+ * <p>
+ * The hash map uses separate chaining for collision resolution. Each bucket in the hash map is a
+ * linked list that stores nodes containing key-value pairs. When a collision occurs (i.e., when
+ * two keys hash to the same index), the new key-value pair is simply added to the corresponding
+ * linked list.
+ * </p>
+ *
+ * <p>
+ * The hash map automatically resizes itself when the load factor exceeds 0.75. 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.
+ * </p>
+ *
+ * @param <K> the type of keys maintained by this hash map
+ * @param <V> the type of mapped values
+ */
 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;
+    private int size; // Total number of key-value pairs
+    private LinkedList<Node>[] buckets; // Array of linked lists (buckets) for storing entries
+    private final float loadFactorThreshold = 0.75f; // Load factor threshold for resizing
 
+    /**
+     * Constructs a new empty hash map with an initial capacity of 16.
+     */
     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.
-
+    /**
+     * Initializes the buckets for the hash map with the specified number of buckets.
+     *
+     * @param n the number of buckets to initialize
+     */
     private void initBuckets(int n) {
         buckets = new LinkedList[n];
         for (int i = 0; i < buckets.length; i++) {
@@ -26,43 +49,65 @@ private void initBuckets(int n) {
         }
     }
 
+    /**
+     * 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 bucketIndex = hashFunction(key);
         LinkedList<Node> nodes = buckets[bucketIndex];
-        for (Node node : nodes) { // if key present => update
+        // Update existing key's value if present
+        for (Node node : nodes) {
             if (node.key.equals(key)) {
                 node.value = value;
                 return;
             }
         }
 
-        // key is not present => insert
+        // Insert new key-value pair
         nodes.add(new Node(key, value));
         size++;
 
-        if ((float) size / buckets.length > lf) {
+        // Check if rehashing is needed
+        if ((float) size / buckets.length > loadFactorThreshold) {
             reHash();
         }
     }
 
-    // tells which bucket to go to
+    /**
+     * Returns the index of the bucket in which the key would be stored.
+     *
+     * @param key the key whose bucket index is to be computed
+     * @return the bucket index
+     */
     private int hashFunction(K key) {
         return Math.floorMod(key.hashCode(), buckets.length);
     }
 
+    /**
+     * Rehashes the map by doubling the number of buckets and re-inserting all entries.
+     */
     private void reHash() {
         System.out.println("Rehashing!");
-        LinkedList<Node>[] old = buckets;
-        initBuckets(old.length * 2);
+        LinkedList<Node>[] oldBuckets = buckets;
+        initBuckets(oldBuckets.length * 2);
         this.size = 0;
 
-        for (LinkedList<Node> nodes : old) {
+        for (LinkedList<Node> nodes : oldBuckets) {
             for (Node node : nodes) {
                 put(node.key, node.value);
             }
         }
     }
 
+    /**
+     * 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 bucketIndex = hashFunction(key);
         LinkedList<Node> nodes = buckets[bucketIndex];
@@ -74,14 +119,28 @@ public void remove(K key) {
                 break;
             }
         }
-        nodes.remove(target);
-        size--;
+
+        if (target != null) {
+            nodes.remove(target);
+            size--;
+        }
     }
 
+    /**
+     * Returns the number of key-value pairs in this map.
+     *
+     * @return the number of key-value pairs
+     */
     public int size() {
         return this.size;
     }
 
+    /**
+     * 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 bucketIndex = hashFunction(key);
         LinkedList<Node> nodes = buckets[bucketIndex];
@@ -96,7 +155,6 @@ public V get(K key) {
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
-
         builder.append("{");
         for (LinkedList<Node> nodes : buckets) {
             for (Node node : nodes) {
@@ -106,19 +164,37 @@ public String toString() {
                 builder.append(", ");
             }
         }
+        // Remove trailing comma and space
+        if (builder.length() > 1) {
+            builder.setLength(builder.length() - 2);
+        }
         builder.append("}");
         return builder.toString();
     }
 
+    /**
+     * 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;
     }
 
+    /**
+     * A private class representing a key-value pair (node) in the hash map.
+     */
     public class Node {
-
         K key;
         V value;
 
+        /**
+         * Constructs a new Node with the specified key and value.
+         *
+         * @param key the key of the key-value pair
+         * @param value the value of the key-value pair
+         */
         public Node(K key, V value) {
             this.key = key;
             this.value = value;
diff --git a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java
index 483e43bb5cb3..5d1733a3e97c 100644
--- a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java
@@ -50,4 +50,47 @@ void testGenericHashmapWhichUsesArrayAndKeyIsIntegerValueIsString() {
         assertEquals("Washington DC", map.get(101));
         assertTrue(map.containsKey(46));
     }
+
+    @Test
+    void testRemoveNonExistentKey() {
+        GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
+        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() {
+        GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
+        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() {
+        GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
+        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() {
+        GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
+        map.put("USA", "Washington DC");
+        map.put("Nepal", "Kathmandu");
+        String expected = "{USA : Washington DC, Nepal : Kathmandu}";
+        assertEquals(expected, map.toString());
+    }
+
+    @Test
+    void testContainsKey() {
+        GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
+        map.put("USA", "Washington DC");
+        assertTrue(map.containsKey("USA"));
+        assertFalse(map.containsKey("Nepal"));
+    }
 }

From 00b0301312457bf0c3563c8925cbb3250a79c247 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <hardikhpawar.cs21@rvce.edu.in>
Date: Thu, 24 Oct 2024 11:29:49 +0530
Subject: [PATCH 2/3] Fix

---
 .../hashmap/hashing/GenericHashMapUsingArray.java              | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
index 5a05d8273f6b..ed89dacd5ffa 100644
--- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
+++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
@@ -27,7 +27,6 @@ public class GenericHashMapUsingArray<K, V> {
 
     private int size; // Total number of key-value pairs
     private LinkedList<Node>[] buckets; // Array of linked lists (buckets) for storing entries
-    private final float loadFactorThreshold = 0.75f; // Load factor threshold for resizing
 
     /**
      * Constructs a new empty hash map with an initial capacity of 16.
@@ -72,6 +71,8 @@ public void put(K key, V value) {
         size++;
 
         // Check if rehashing is needed
+        // Load factor threshold for resizing
+        float loadFactorThreshold = 0.75f;
         if ((float) size / buckets.length > loadFactorThreshold) {
             reHash();
         }

From 57a26e64ffa737ee8beb981943bd3001eaba16b7 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <hardikhpawar.cs21@rvce.edu.in>
Date: Tue, 29 Oct 2024 10:04:06 +0530
Subject: [PATCH 3/3] Fix

---
 .../datastructures/hashmap/hashing/GenericHashMapUsingArray.java | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
index ed89dacd5ffa..3637e323f097 100644
--- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
+++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
@@ -92,7 +92,6 @@ private int hashFunction(K key) {
      * Rehashes the map by doubling the number of buckets and re-inserting all entries.
      */
     private void reHash() {
-        System.out.println("Rehashing!");
         LinkedList<Node>[] oldBuckets = buckets;
         initBuckets(oldBuckets.length * 2);
         this.size = 0;