Skip to content

Commit 63d13b6

Browse files
authored
Enhance docs, add tests in GenericHashMapUsingArray (TheAlgorithms#5972)
1 parent fd14016 commit 63d13b6

File tree

2 files changed

+140
-21
lines changed

2 files changed

+140
-21
lines changed

src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java

Lines changed: 97 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,112 @@
22

33
import java.util.LinkedList;
44

5-
// implementation of generic hashmaps using array of Linked Lists
6-
5+
/**
6+
* A generic implementation of a hash map using an array of linked lists for collision resolution.
7+
* This class provides a way to store key-value pairs efficiently, allowing for average-case
8+
* constant time complexity for insertion, deletion, and retrieval operations.
9+
*
10+
* <p>
11+
* The hash map uses separate chaining for collision resolution. Each bucket in the hash map is a
12+
* linked list that stores nodes containing key-value pairs. When a collision occurs (i.e., when
13+
* two keys hash to the same index), the new key-value pair is simply added to the corresponding
14+
* linked list.
15+
* </p>
16+
*
17+
* <p>
18+
* The hash map automatically resizes itself when the load factor exceeds 0.75. The load factor is
19+
* defined as the ratio of the number of entries to the number of buckets. When resizing occurs,
20+
* all existing entries are rehashed and inserted into the new buckets.
21+
* </p>
22+
*
23+
* @param <K> the type of keys maintained by this hash map
24+
* @param <V> the type of mapped values
25+
*/
726
public class GenericHashMapUsingArray<K, V> {
827

9-
private int size; // n (total number of key-value pairs)
10-
private LinkedList<Node>[] buckets; // N = buckets.length
11-
private float lf = 0.75f;
28+
private int size; // Total number of key-value pairs
29+
private LinkedList<Node>[] buckets; // Array of linked lists (buckets) for storing entries
1230

31+
/**
32+
* Constructs a new empty hash map with an initial capacity of 16.
33+
*/
1334
public GenericHashMapUsingArray() {
1435
initBuckets(16);
1536
size = 0;
1637
}
1738

18-
// load factor = 0.75 means if we need to add 100 items and we have added
19-
// 75, then adding 76th item it will double the size, copy all elements
20-
// & then add 76th item.
21-
39+
/**
40+
* Initializes the buckets for the hash map with the specified number of buckets.
41+
*
42+
* @param n the number of buckets to initialize
43+
*/
2244
private void initBuckets(int n) {
2345
buckets = new LinkedList[n];
2446
for (int i = 0; i < buckets.length; i++) {
2547
buckets[i] = new LinkedList<>();
2648
}
2749
}
2850

51+
/**
52+
* Associates the specified value with the specified key in this map.
53+
* If the map previously contained a mapping for the key, the old value is replaced.
54+
*
55+
* @param key the key with which the specified value is to be associated
56+
* @param value the value to be associated with the specified key
57+
*/
2958
public void put(K key, V value) {
3059
int bucketIndex = hashFunction(key);
3160
LinkedList<Node> nodes = buckets[bucketIndex];
32-
for (Node node : nodes) { // if key present => update
61+
// Update existing key's value if present
62+
for (Node node : nodes) {
3363
if (node.key.equals(key)) {
3464
node.value = value;
3565
return;
3666
}
3767
}
3868

39-
// key is not present => insert
69+
// Insert new key-value pair
4070
nodes.add(new Node(key, value));
4171
size++;
4272

43-
if ((float) size / buckets.length > lf) {
73+
// Check if rehashing is needed
74+
// Load factor threshold for resizing
75+
float loadFactorThreshold = 0.75f;
76+
if ((float) size / buckets.length > loadFactorThreshold) {
4477
reHash();
4578
}
4679
}
4780

48-
// tells which bucket to go to
81+
/**
82+
* Returns the index of the bucket in which the key would be stored.
83+
*
84+
* @param key the key whose bucket index is to be computed
85+
* @return the bucket index
86+
*/
4987
private int hashFunction(K key) {
5088
return Math.floorMod(key.hashCode(), buckets.length);
5189
}
5290

91+
/**
92+
* Rehashes the map by doubling the number of buckets and re-inserting all entries.
93+
*/
5394
private void reHash() {
54-
System.out.println("Rehashing!");
55-
LinkedList<Node>[] old = buckets;
56-
initBuckets(old.length * 2);
95+
LinkedList<Node>[] oldBuckets = buckets;
96+
initBuckets(oldBuckets.length * 2);
5797
this.size = 0;
5898

59-
for (LinkedList<Node> nodes : old) {
99+
for (LinkedList<Node> nodes : oldBuckets) {
60100
for (Node node : nodes) {
61101
put(node.key, node.value);
62102
}
63103
}
64104
}
65105

106+
/**
107+
* Removes the mapping for the specified key from this map if present.
108+
*
109+
* @param key the key whose mapping is to be removed from the map
110+
*/
66111
public void remove(K key) {
67112
int bucketIndex = hashFunction(key);
68113
LinkedList<Node> nodes = buckets[bucketIndex];
@@ -74,14 +119,28 @@ public void remove(K key) {
74119
break;
75120
}
76121
}
77-
nodes.remove(target);
78-
size--;
122+
123+
if (target != null) {
124+
nodes.remove(target);
125+
size--;
126+
}
79127
}
80128

129+
/**
130+
* Returns the number of key-value pairs in this map.
131+
*
132+
* @return the number of key-value pairs
133+
*/
81134
public int size() {
82135
return this.size;
83136
}
84137

138+
/**
139+
* Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
140+
*
141+
* @param key the key whose associated value is to be returned
142+
* @return the value associated with the specified key, or null if no mapping exists
143+
*/
85144
public V get(K key) {
86145
int bucketIndex = hashFunction(key);
87146
LinkedList<Node> nodes = buckets[bucketIndex];
@@ -96,7 +155,6 @@ public V get(K key) {
96155
@Override
97156
public String toString() {
98157
StringBuilder builder = new StringBuilder();
99-
100158
builder.append("{");
101159
for (LinkedList<Node> nodes : buckets) {
102160
for (Node node : nodes) {
@@ -106,19 +164,37 @@ public String toString() {
106164
builder.append(", ");
107165
}
108166
}
167+
// Remove trailing comma and space
168+
if (builder.length() > 1) {
169+
builder.setLength(builder.length() - 2);
170+
}
109171
builder.append("}");
110172
return builder.toString();
111173
}
112174

175+
/**
176+
* Returns true if this map contains a mapping for the specified key.
177+
*
178+
* @param key the key whose presence in this map is to be tested
179+
* @return true if this map contains a mapping for the specified key
180+
*/
113181
public boolean containsKey(K key) {
114182
return get(key) != null;
115183
}
116184

185+
/**
186+
* A private class representing a key-value pair (node) in the hash map.
187+
*/
117188
public class Node {
118-
119189
K key;
120190
V value;
121191

192+
/**
193+
* Constructs a new Node with the specified key and value.
194+
*
195+
* @param key the key of the key-value pair
196+
* @param value the value of the key-value pair
197+
*/
122198
public Node(K key, V value) {
123199
this.key = key;
124200
this.value = value;

src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,47 @@ void testGenericHashmapWhichUsesArrayAndKeyIsIntegerValueIsString() {
5050
assertEquals("Washington DC", map.get(101));
5151
assertTrue(map.containsKey(46));
5252
}
53+
54+
@Test
55+
void testRemoveNonExistentKey() {
56+
GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
57+
map.put("USA", "Washington DC");
58+
map.remove("Nepal"); // Attempting to remove a non-existent key
59+
assertEquals(1, map.size()); // Size should remain the same
60+
}
61+
62+
@Test
63+
void testRehashing() {
64+
GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
65+
for (int i = 0; i < 20; i++) {
66+
map.put("Key" + i, "Value" + i);
67+
}
68+
assertEquals(20, map.size()); // Ensure all items were added
69+
assertEquals("Value5", map.get("Key5")); // Check retrieval after rehash
70+
}
71+
72+
@Test
73+
void testUpdateValueForExistingKey() {
74+
GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
75+
map.put("USA", "Washington DC");
76+
map.put("USA", "New Washington DC"); // Updating value for existing key
77+
assertEquals("New Washington DC", map.get("USA"));
78+
}
79+
80+
@Test
81+
void testToStringMethod() {
82+
GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
83+
map.put("USA", "Washington DC");
84+
map.put("Nepal", "Kathmandu");
85+
String expected = "{USA : Washington DC, Nepal : Kathmandu}";
86+
assertEquals(expected, map.toString());
87+
}
88+
89+
@Test
90+
void testContainsKey() {
91+
GenericHashMapUsingArray<String, String> map = new GenericHashMapUsingArray<>();
92+
map.put("USA", "Washington DC");
93+
assertTrue(map.containsKey("USA"));
94+
assertFalse(map.containsKey("Nepal"));
95+
}
5396
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy