Repository: TheAlgorithms/Java
Pull request #5972 (2024-10-24 05:53:49)

refactor: Enhance docs, add tests in `GenericHashMapUsingArray`
<!--
Thank you for your contribution!
In order to reduce the number of notifications sent to the maintainers, please:
- create your PR as draft, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests,
- make sure that all of the CI checks pass,
- mark your PR as ready for review, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#marking-a-pull-request-as-ready-for-review
-->

<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.
- [x] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`

codecov-commenter: ## [Codecov](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5972?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) Report
Attention: Patch coverage is `90.90909%` with `1 line` in your changes missing coverage. Please review.
> Project coverage is 68.14%. Comparing base [(`13be250`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/13be2501c29c0997c511f39aa9fe33957a1ea132?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) to head [(`b8a5023`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/b8a502399e43da9d122e728041ceca3723786f27?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).
> Report is 3 commits behind head on master.

| [Files with missing lines](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5972?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) | Patch % | Lines |
|---|---|---|
| [...ures/hashmap/hashing/GenericHashMapUsingArray.java](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5972?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fcom%2Fthealgorithms%2Fdatastructures%2Fhashmap%2Fhashing%2FGenericHashMapUsingArray.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms#diff-c3JjL21haW4vamF2YS9jb20vdGhlYWxnb3JpdGhtcy9kYXRhc3RydWN0dXJlcy9oYXNobWFwL2hhc2hpbmcvR2VuZXJpY0hhc2hNYXBVc2luZ0FycmF5LmphdmE=) | 90.90% | [0 Missing and 1 partial :warning: ](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5972?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##             master    #5972      +/-   ##
============================================
+ Coverage     67.69%   68.14%   +0.44%     
- Complexity     4577     4597      +20     
============================================
  Files           620      620              
  Lines         17145    17119      -26     
  Branches       3311     3307       -4     
============================================
+ Hits          11607    11666      +59     
+ Misses         5093     5010      -83     
+ Partials        445      443       -2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5972?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).


Patch:
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 416cee99..3637e323 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,45 @@ package com.thealgorithms.datastructures.hashmap.hashing;
 
 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
 
+    /**
+     * 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 +48,66 @@ public class GenericHashMapUsingArray<K, V> {
         }
     }
 
+    /**
+     * 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
+        // Load factor threshold for resizing
+        float loadFactorThreshold = 0.75f;
+        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 class GenericHashMapUsingArray<K, V> {
                 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 class GenericHashMapUsingArray<K, V> {
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
-
         builder.append("{");
         for (LinkedList<Node> nodes : buckets) {
             for (Node node : nodes) {
@@ -106,19 +164,37 @@ public class GenericHashMapUsingArray<K, V> {
                 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;


Test patch:
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 483e43bb..5d1733a3 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 @@ class GenericHashMapUsingArrayTest {
         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"));
+    }
 }