From ffd02504d924f8586409fa39f379c505d187f6d0 Mon Sep 17 00:00:00 2001 From: Divya Raichura <92081543+divya-raichura@users.noreply.github.com> Date: Mon, 18 Jul 2022 01:30:55 +0530 Subject: [PATCH] Add generic hashmaps (#3195) --- .../hashing/GenericHashMapUsingArray.java | 125 ++++++++++++++++++ .../hashing/GenericHashMapUsingArrayList.java | 112 ++++++++++++++++ .../GenericHashMapUsingArrayListTest.java | 49 +++++++ .../hashing/GenericHashMapUsingArrayTest.java | 49 +++++++ 4 files changed, 335 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java create mode 100644 src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java create mode 100644 src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java create mode 100644 src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java 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 000000000..5b20e56f3 --- /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 { + private int size; // n (total number of key-value pairs) + private LinkedList[] 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 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[] old = buckets; + initBuckets(old.length * 2); + this.size = 0; + + for (LinkedList nodes : old) { + for (Node node : nodes) { + put(node.key, node.value); + } + } + } + + public void remove(K key) { + int bucketIndex = hashFunction(key); + LinkedList 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 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 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 000000000..1702b3b28 --- /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 { + ArrayList> 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 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> old = buckets; + buckets = new ArrayList<>(); + size = 0; + for (int i = 0; i < old.size() * 2; i++) { + buckets.add(new LinkedList<>()); + } + for (LinkedList 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 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 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 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; + } + } + +} 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 000000000..dde9effb7 --- /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 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 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 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 000000000..1e2dfe2f2 --- /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 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 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 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