Skip to content

Commit 324e8f2

Browse files
Fix: Correct HashMap size tracking and refactor LinkedList methods
Added currentSize to track the number of key-value pairs. Updated insert and delete methods to modify currentSize based on key existence. Improved encapsulation by changing LinkedList methods to return values directly and added comments for clarity.
1 parent a14e1e3 commit 324e8f2

File tree

1 file changed

+70
-88
lines changed
  • src/main/java/com/thealgorithms/datastructures/hashmap/hashing

1 file changed

+70
-88
lines changed

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

Lines changed: 70 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
@SuppressWarnings("rawtypes")
1212
public class HashMap<K, V> {
1313
private final int hashSize;
14+
private int currentSize; // Correctly track the total number of key-value pairs
1415
private final LinkedList<K, V>[] buckets;
1516

1617
/**
@@ -21,6 +22,7 @@ public class HashMap<K, V> {
2122
@SuppressWarnings("unchecked")
2223
public HashMap(int hashSize) {
2324
this.hashSize = hashSize;
25+
this.currentSize = 0;
2426
// Safe to suppress warning because we are creating an array of generic type
2527
this.buckets = new LinkedList[hashSize];
2628
for (int i = 0; i < hashSize; i++) {
@@ -37,9 +39,10 @@ public HashMap(int hashSize) {
3739
*/
3840
private int computeHash(K key) {
3941
if (key == null) {
40-
return 0; // Use a special bucket (e.g., bucket 0) for null keys
42+
return 0; // Use bucket 0 for null keys
4143
}
4244
int hash = key.hashCode() % hashSize;
45+
// Ensure the hash index is non-negative
4346
return hash < 0 ? hash + hashSize : hash;
4447
}
4548

@@ -52,7 +55,12 @@ private int computeHash(K key) {
5255
*/
5356
public void insert(K key, V value) {
5457
int hash = computeHash(key);
55-
buckets[hash].insert(key, value);
58+
boolean keyExisted = buckets[hash].insert(key, value);
59+
60+
// Only increment size if a new key was inserted (not an update)
61+
if (!keyExisted) {
62+
currentSize++;
63+
}
5664
}
5765

5866
/**
@@ -62,7 +70,12 @@ public void insert(K key, V value) {
6270
*/
6371
public void delete(K key) {
6472
int hash = computeHash(key);
65-
buckets[hash].delete(key);
73+
boolean deletedSuccessfully = buckets[hash].delete(key);
74+
75+
// Only decrement size if deletion was successful
76+
if (deletedSuccessfully) {
77+
currentSize--;
78+
}
6679
}
6780

6881
/**
@@ -73,8 +86,8 @@ public void delete(K key) {
7386
*/
7487
public V search(K key) {
7588
int hash = computeHash(key);
76-
Node<K, V> node = buckets[hash].findKey(key);
77-
return node != null ? node.getValue() : null;
89+
// Changed LinkedList to return the value directly for better encapsulation
90+
return buckets[hash].findValue(key);
7891
}
7992

8093
/**
@@ -87,80 +100,71 @@ public void display() {
87100
}
88101

89102
/**
90-
* Clears the contents of the hash map by reinitializing each bucket.
103+
* Clears the contents of the hash map by reinitializing each bucket and resetting the size.
91104
*/
92105
public void clear() {
93106
for (int i = 0; i < hashSize; i++) {
94107
buckets[i] = new LinkedList<>();
95108
}
109+
currentSize = 0; // Reset size
96110
}
97111

98112
/**
99113
* Gets the number of key-value pairs in the hash map.
114+
* Corrected to return the stored 'currentSize' in O(1) time.
100115
*
101116
* @return the number of key-value pairs in the hash map
102117
*/
103118
public int size() {
104-
int size = 0;
105-
for (int i = 0; i < hashSize; i++) {
106-
size += buckets[i].isEmpty() ? 0 : 1;
107-
}
108-
return size;
119+
return currentSize;
109120
}
110121

122+
// --- NESTED LINKED LIST CLASS (Collision Handler) ---
123+
111124
/**
112125
* A nested static class that represents a linked list used for separate chaining in the hash map.
113-
*
114-
* @param <K> the type of keys maintained by this linked list
115-
* @param <V> the type of mapped values
116126
*/
117127
public static class LinkedList<K, V> {
118128
private Node<K, V> head;
119129

120130
/**
121131
* Inserts the specified key-value pair into the linked list.
122-
* If the linked list is empty, the pair becomes the head.
123-
* Otherwise, the pair is added to the end of the list.
132+
* If the key already exists, the value is updated.
124133
*
125134
* @param key the key to be inserted
126135
* @param value the value to be associated with the key
136+
* @return true if an existing key was updated, false if a new node was created.
127137
*/
128-
public void insert(K key, V value) {
129-
Node<K, V> existingNode = findKey(key);
138+
public boolean insert(K key, V value) {
139+
Node<K, V> existingNode = findNode(key);
130140
if (existingNode != null) {
131-
existingNode.setValue(value); // Update the value, even if it's null
141+
existingNode.setValue(value);
142+
return true; // Key existed, value updated
132143
} else {
144+
Node<K, V> newNode = new Node<>(key, value);
133145
if (isEmpty()) {
134-
head = new Node<>(key, value);
146+
head = newNode;
135147
} else {
136-
Node<K, V> temp = findEnd(head);
137-
temp.setNext(new Node<>(key, value));
148+
Node<K, V> temp = head; // Start search from head
149+
while (temp.getNext() != null) {
150+
temp = temp.getNext();
151+
}
152+
temp.setNext(newNode);
138153
}
154+
return false; // New key added
139155
}
140156
}
141157

142158
/**
143-
* Finds the last node in the linked list.
144-
*
145-
* @param node the starting node
146-
* @return the last node in the linked list
147-
*/
148-
private Node<K, V> findEnd(Node<K, V> node) {
149-
while (node.getNext() != null) {
150-
node = node.getNext();
151-
}
152-
return node;
153-
}
154-
155-
/**
156-
* Finds the node associated with the specified key in the linked list.
159+
* Finds the node associated with the specified key.
157160
*
158161
* @param key the key to search for
159162
* @return the node associated with the specified key, or null if not found
160163
*/
161-
public Node<K, V> findKey(K key) {
164+
private Node<K, V> findNode(K key) {
162165
Node<K, V> temp = head;
163166
while (temp != null) {
167+
// Robust key comparison, handles null keys correctly
164168
if ((key == null && temp.getKey() == null) || (temp.getKey() != null && temp.getKey().equals(key))) {
165169
return temp;
166170
}
@@ -169,32 +173,46 @@ public Node<K, V> findKey(K key) {
169173
return null;
170174
}
171175

176+
/**
177+
* Finds the value associated with the specified key.
178+
*
179+
* @param key the key to search for
180+
* @return the value associated with the specified key, or null if not found
181+
*/
182+
public V findValue(K key) {
183+
Node<K, V> node = findNode(key);
184+
return node != null ? node.getValue() : null;
185+
}
186+
187+
172188
/**
173189
* Deletes the node associated with the specified key from the linked list.
174-
* Handles the case where the key could be null.
175190
*
176191
* @param key the key whose associated node is to be deleted
192+
* @return true if the node was successfully deleted, false otherwise.
177193
*/
178-
public void delete(K key) {
194+
public boolean delete(K key) {
179195
if (isEmpty()) {
180-
return;
196+
return false;
181197
}
182198

183-
// Handle the case where the head node has the key to delete
199+
// Handle head deletion
184200
if ((key == null && head.getKey() == null) || (head.getKey() != null && head.getKey().equals(key))) {
185201
head = head.getNext();
186-
return;
202+
return true;
187203
}
188204

189-
// Traverse the list to find and delete the node
205+
// Traverse to find node to delete
190206
Node<K, V> current = head;
191207
while (current.getNext() != null) {
192-
if ((key == null && current.getNext().getKey() == null) || (current.getNext().getKey() != null && current.getNext().getKey().equals(key))) {
193-
current.setNext(current.getNext().getNext());
194-
return;
208+
Node<K, V> nextNode = current.getNext();
209+
if ((key == null && nextNode.getKey() == null) || (nextNode.getKey() != null && nextNode.getKey().equals(key))) {
210+
current.setNext(nextNode.getNext());
211+
return true;
195212
}
196213
current = current.getNext();
197214
}
215+
return false; // Key not found
198216
}
199217

200218
/**
@@ -203,25 +221,16 @@ public void delete(K key) {
203221
* @return a string representation of the linked list
204222
*/
205223
public String display() {
206-
return display(head);
207-
}
208-
209-
/**
210-
* Constructs a string representation of the linked list non-recursively.
211-
*
212-
* @param node the starting node
213-
* @return a string representation of the linked list starting from the given node
214-
*/
215-
private String display(Node<K, V> node) {
216224
StringBuilder sb = new StringBuilder();
225+
Node<K, V> node = head;
217226
while (node != null) {
218227
sb.append(node.getKey()).append("=").append(node.getValue());
219228
node = node.getNext();
220229
if (node != null) {
221230
sb.append(" -> ");
222231
}
223232
}
224-
return sb.toString().isEmpty() ? "null" : sb.toString();
233+
return sb.length() > 0 ? sb.toString() : "empty";
225234
}
226235

227236
/**
@@ -234,64 +243,37 @@ public boolean isEmpty() {
234243
}
235244
}
236245

246+
// --- NESTED NODE CLASS (Key-Value Pair) ---
247+
237248
/**
238-
* A nested static class representing a node in the linked list.
239-
*
240-
* @param <K> the type of key maintained by this node
241-
* @param <V> the type of value maintained by this node
249+
* A nested static class representing a node (Entry) in the linked list.
242250
*/
243251
public static class Node<K, V> {
244252
private final K key;
245253
private V value;
246254
private Node<K, V> next;
247255

248-
/**
249-
* Constructs a Node with the specified key and value.
250-
*
251-
* @param key the key associated with this node
252-
* @param value the value associated with this node
253-
*/
254256
public Node(K key, V value) {
255257
this.key = key;
256258
this.value = value;
257259
}
258260

259-
/**
260-
* Gets the key associated with this node.
261-
*
262-
* @return the key associated with this node
263-
*/
264261
public K getKey() {
265262
return key;
266263
}
267264

268-
/**
269-
* Gets the value associated with this node.
270-
*
271-
* @return the value associated with this node
272-
*/
273265
public V getValue() {
274266
return value;
275267
}
276268

277-
public void setValue(V value) { // This method allows updating the value
269+
public void setValue(V value) {
278270
this.value = value;
279271
}
280272

281-
/**
282-
* Gets the next node in the linked list.
283-
*
284-
* @return the next node in the linked list
285-
*/
286273
public Node<K, V> getNext() {
287274
return next;
288275
}
289276

290-
/**
291-
* Sets the next node in the linked list.
292-
*
293-
* @param next the next node to be linked
294-
*/
295277
public void setNext(Node<K, V> next) {
296278
this.next = next;
297279
}

0 commit comments

Comments
 (0)