Skip to content

Commit a23e9b0

Browse files
alxkmalxkm
and
alxkm
authored
refactor: HashMap (#5426)
* refactor: HashMap * checkstyle: fix formatting * refactor: remove redundant comments --------- Co-authored-by: alxkm <[email protected]>
1 parent 6b7a1fd commit a23e9b0

File tree

3 files changed

+364
-141
lines changed

3 files changed

+364
-141
lines changed

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

+218-89
Original file line numberDiff line numberDiff line change
@@ -1,146 +1,275 @@
11
package com.thealgorithms.datastructures.hashmap.hashing;
22

3-
public class HashMap {
3+
/**
4+
* A generic HashMap implementation that uses separate chaining with linked lists
5+
* to handle collisions. The class supports basic operations such as insert, delete,
6+
* and search, as well as displaying the contents of the hash map.
7+
*
8+
* @param <K> the type of keys maintained by this map
9+
* @param <V> the type of mapped values
10+
*/
11+
public class HashMap<K, V> {
12+
private final int hashSize;
13+
private final LinkedList<K, V>[] buckets;
414

5-
private final int hsize;
6-
private final LinkedList[] buckets;
7-
8-
public HashMap(int hsize) {
9-
buckets = new LinkedList[hsize];
10-
for (int i = 0; i < hsize; i++) {
11-
buckets[i] = new LinkedList();
12-
// Java requires explicit initialization of each object
15+
/**
16+
* Constructs a HashMap with the specified hash size.
17+
*
18+
* @param hashSize the number of buckets in the hash map
19+
*/
20+
@SuppressWarnings("unchecked")
21+
public HashMap(int hashSize) {
22+
this.hashSize = hashSize;
23+
// Safe to suppress warning because we are creating an array of generic type
24+
this.buckets = new LinkedList[hashSize];
25+
for (int i = 0; i < hashSize; i++) {
26+
buckets[i] = new LinkedList<>();
1327
}
14-
this.hsize = hsize;
1528
}
1629

17-
public int hashing(int key) {
18-
int hash = key % hsize;
19-
if (hash < 0) {
20-
hash += hsize;
30+
/**
31+
* Computes the hash code for the specified key.
32+
* Null keys are hashed to bucket 0.
33+
*
34+
* @param key the key for which the hash code is to be computed
35+
* @return the hash code corresponding to the key
36+
*/
37+
private int computeHash(K key) {
38+
if (key == null) {
39+
return 0; // Use a special bucket (e.g., bucket 0) for null keys
2140
}
22-
return hash;
41+
int hash = key.hashCode() % hashSize;
42+
return hash < 0 ? hash + hashSize : hash;
2343
}
2444

25-
public void insertHash(int key) {
26-
int hash = hashing(key);
27-
buckets[hash].insert(key);
45+
/**
46+
* Inserts the specified key-value pair into the hash map.
47+
* If the key already exists, the value is updated.
48+
*
49+
* @param key the key to be inserted
50+
* @param value the value to be associated with the key
51+
*/
52+
public void insert(K key, V value) {
53+
int hash = computeHash(key);
54+
buckets[hash].insert(key, value);
2855
}
2956

30-
public void deleteHash(int key) {
31-
int hash = hashing(key);
32-
57+
/**
58+
* Deletes the key-value pair associated with the specified key from the hash map.
59+
*
60+
* @param key the key whose key-value pair is to be deleted
61+
*/
62+
public void delete(K key) {
63+
int hash = computeHash(key);
3364
buckets[hash].delete(key);
3465
}
3566

36-
public void displayHashtable() {
37-
for (int i = 0; i < hsize; i++) {
38-
System.out.printf("Bucket %d :", i);
39-
System.out.println(buckets[i].display());
40-
}
67+
/**
68+
* Searches for the value associated with the specified key in the hash map.
69+
*
70+
* @param key the key whose associated value is to be returned
71+
* @return the value associated with the specified key, or null if the key does not exist
72+
*/
73+
public V search(K key) {
74+
int hash = computeHash(key);
75+
Node<K, V> node = buckets[hash].findKey(key);
76+
return node != null ? node.getValue() : null;
4177
}
4278

43-
public static class LinkedList {
44-
45-
private Node first;
46-
47-
public LinkedList() {
48-
first = null;
79+
/**
80+
* Displays the contents of the hash map, showing each bucket and its key-value pairs.
81+
*/
82+
public void display() {
83+
for (int i = 0; i < hashSize; i++) {
84+
System.out.printf("Bucket %d: %s%n", i, buckets[i].display());
4985
}
86+
}
5087

51-
public void insert(int key) {
52-
if (isEmpty()) {
53-
first = new Node(key);
54-
return;
55-
}
88+
/**
89+
* A nested static class that represents a linked list used for separate chaining in the hash map.
90+
*
91+
* @param <K> the type of keys maintained by this linked list
92+
* @param <V> the type of mapped values
93+
*/
94+
public static class LinkedList<K, V> {
95+
private Node<K, V> head;
5696

57-
Node temp = findEnd(first);
58-
temp.setNext(new Node(key));
97+
/**
98+
* Inserts the specified key-value pair into the linked list.
99+
* If the linked list is empty, the pair becomes the head.
100+
* Otherwise, the pair is added to the end of the list.
101+
*
102+
* @param key the key to be inserted
103+
* @param value the value to be associated with the key
104+
*/
105+
public void insert(K key, V value) {
106+
Node<K, V> existingNode = findKey(key);
107+
if (existingNode != null) {
108+
existingNode.setValue(value); // Update the value, even if it's null
109+
} else {
110+
if (isEmpty()) {
111+
head = new Node<>(key, value);
112+
} else {
113+
Node<K, V> temp = findEnd(head);
114+
temp.setNext(new Node<>(key, value));
115+
}
116+
}
59117
}
60118

61-
private Node findEnd(Node n) {
62-
while (n.getNext() != null) {
63-
n = n.getNext();
119+
/**
120+
* Finds the last node in the linked list.
121+
*
122+
* @param node the starting node
123+
* @return the last node in the linked list
124+
*/
125+
private Node<K, V> findEnd(Node<K, V> node) {
126+
while (node.getNext() != null) {
127+
node = node.getNext();
64128
}
65-
return n;
129+
return node;
66130
}
67131

68-
public Node findKey(int key) {
69-
if (!isEmpty()) {
70-
Node temp = first;
71-
if (temp.getKey() == key) {
132+
/**
133+
* Finds the node associated with the specified key in the linked list.
134+
*
135+
* @param key the key to search for
136+
* @return the node associated with the specified key, or null if not found
137+
*/
138+
public Node<K, V> findKey(K key) {
139+
Node<K, V> temp = head;
140+
while (temp != null) {
141+
if ((key == null && temp.getKey() == null) || (temp.getKey() != null && temp.getKey().equals(key))) {
72142
return temp;
73143
}
74-
75-
while ((temp = temp.getNext()) != null) {
76-
if (temp.getKey() == key) {
77-
return temp;
78-
}
79-
}
144+
temp = temp.getNext();
80145
}
81146
return null;
82147
}
83148

84-
public void delete(int key) {
85-
if (!isEmpty()) {
86-
if (first.getKey() == key) {
87-
Node next = first.next;
88-
first.next = null; // help GC
89-
first = next;
90-
} else {
91-
delete(first, key);
92-
}
149+
/**
150+
* Deletes the node associated with the specified key from the linked list.
151+
* Handles the case where the key could be null.
152+
*
153+
* @param key the key whose associated node is to be deleted
154+
*/
155+
public void delete(K key) {
156+
if (isEmpty()) {
157+
return;
93158
}
94-
}
95159

96-
private void delete(Node n, int key) {
97-
if (n.getNext().getKey() == key) {
98-
if (n.getNext().getNext() == null) {
99-
n.setNext(null);
100-
} else {
101-
n.setNext(n.getNext().getNext());
160+
// Handle the case where the head node has the key to delete
161+
if ((key == null && head.getKey() == null) || (head.getKey() != null && head.getKey().equals(key))) {
162+
head = head.getNext();
163+
return;
164+
}
165+
166+
// Traverse the list to find and delete the node
167+
Node<K, V> current = head;
168+
while (current.getNext() != null) {
169+
if ((key == null && current.getNext().getKey() == null) || (current.getNext().getKey() != null && current.getNext().getKey().equals(key))) {
170+
current.setNext(current.getNext().getNext());
171+
return;
102172
}
103-
} else {
104-
delete(n.getNext(), key);
173+
current = current.getNext();
105174
}
106175
}
107176

177+
/**
178+
* Displays the contents of the linked list as a string.
179+
*
180+
* @return a string representation of the linked list
181+
*/
108182
public String display() {
109-
return display(first);
183+
return display(head);
110184
}
111185

112-
private String display(Node n) {
113-
if (n == null) {
114-
return "null";
115-
} else {
116-
return n.getKey() + "->" + display(n.getNext());
186+
/**
187+
* Constructs a string representation of the linked list non-recursively.
188+
*
189+
* @param node the starting node
190+
* @return a string representation of the linked list starting from the given node
191+
*/
192+
private String display(Node<K, V> node) {
193+
StringBuilder sb = new StringBuilder();
194+
while (node != null) {
195+
sb.append(node.getKey()).append("=").append(node.getValue());
196+
node = node.getNext();
197+
if (node != null) {
198+
sb.append(" -> ");
199+
}
117200
}
201+
return sb.toString().isEmpty() ? "null" : sb.toString();
118202
}
119203

204+
/**
205+
* Checks if the linked list is empty.
206+
*
207+
* @return true if the linked list is empty, false otherwise
208+
*/
120209
public boolean isEmpty() {
121-
return first == null;
210+
return head == null;
122211
}
123212
}
124213

125-
public static class Node {
214+
/**
215+
* A nested static class representing a node in the linked list.
216+
*
217+
* @param <K> the type of key maintained by this node
218+
* @param <V> the type of value maintained by this node
219+
*/
220+
public static class Node<K, V> {
221+
private final K key;
222+
private V value;
223+
private Node<K, V> next;
126224

127-
private Node next;
128-
private final int key;
129-
130-
public Node(int key) {
131-
next = null;
225+
/**
226+
* Constructs a Node with the specified key and value.
227+
*
228+
* @param key the key associated with this node
229+
* @param value the value associated with this node
230+
*/
231+
public Node(K key, V value) {
132232
this.key = key;
233+
this.value = value;
133234
}
134235

135-
public Node getNext() {
136-
return next;
236+
/**
237+
* Gets the key associated with this node.
238+
*
239+
* @return the key associated with this node
240+
*/
241+
public K getKey() {
242+
return key;
137243
}
138244

139-
public int getKey() {
140-
return key;
245+
/**
246+
* Gets the value associated with this node.
247+
*
248+
* @return the value associated with this node
249+
*/
250+
public V getValue() {
251+
return value;
252+
}
253+
254+
public void setValue(V value) { // This method allows updating the value
255+
this.value = value;
256+
}
257+
258+
/**
259+
* Gets the next node in the linked list.
260+
*
261+
* @return the next node in the linked list
262+
*/
263+
public Node<K, V> getNext() {
264+
return next;
141265
}
142266

143-
public void setNext(Node next) {
267+
/**
268+
* Sets the next node in the linked list.
269+
*
270+
* @param next the next node to be linked
271+
*/
272+
public void setNext(Node<K, V> next) {
144273
this.next = next;
145274
}
146275
}

0 commit comments

Comments
 (0)