Repository: TheAlgorithms/Java
Pull request #3195 (2022-07-16 06:48:06)

implementation of generic hashmaps
### **Describe your change:**

- [x] Add an algorithm?
- [ ] Fix a bug or typo in an existing algorithm?
- [ ] Documentation change?

#### References
- Implementation of generic hashmaps #3193

<!-- Add any reference to previous pull-request or issue -->

### **Checklist:**

<!-- Remove items that do not apply. 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.
- [x] I know that pull requests will not be merged if they fail the automated tests.
- [x] This PR only changes one algorithm file. To ease review, please open separate PRs for separate algorithms.
- [x] All new Java files are placed inside an existing directory.
- [x] All filenames are in all uppercase characters with no spaces or dashes.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in its comments that points to Wikipedia or other similar explanation.
- [x] If this pull request resolves one or more open issues then the commit message contains `Fixes: #{$ISSUE_NO}`.



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
new file mode 100644
index 00000000..5b20e56f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
@@ -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;
+        }
+    }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java
new file mode 100644
index 00000000..1702b3b2
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java
@@ -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;
+        }
+    }
+
+}


Test patch:
diff --git a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java
new file mode 100644
index 00000000..dde9effb
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java
@@ -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));
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java
new file mode 100644
index 00000000..1e2dfe2f
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java
@@ -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));
+    }
+}
\ No newline at end of file