2
2
3
3
import java .util .LinkedList ;
4
4
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
+ */
7
26
public class GenericHashMapUsingArray <K , V > {
8
27
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
30
+ private final float loadFactorThreshold = 0.75f ; // Load factor threshold for resizing
12
31
32
+ /**
33
+ * Constructs a new empty hash map with an initial capacity of 16.
34
+ */
13
35
public GenericHashMapUsingArray () {
14
36
initBuckets (16 );
15
37
size = 0 ;
16
38
}
17
39
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
-
40
+ /**
41
+ * Initializes the buckets for the hash map with the specified number of buckets.
42
+ *
43
+ * @param n the number of buckets to initialize
44
+ */
22
45
private void initBuckets (int n ) {
23
46
buckets = new LinkedList [n ];
24
47
for (int i = 0 ; i < buckets .length ; i ++) {
25
48
buckets [i ] = new LinkedList <>();
26
49
}
27
50
}
28
51
52
+ /**
53
+ * Associates the specified value with the specified key in this map.
54
+ * If the map previously contained a mapping for the key, the old value is replaced.
55
+ *
56
+ * @param key the key with which the specified value is to be associated
57
+ * @param value the value to be associated with the specified key
58
+ */
29
59
public void put (K key , V value ) {
30
60
int bucketIndex = hashFunction (key );
31
61
LinkedList <Node > nodes = buckets [bucketIndex ];
32
- for (Node node : nodes ) { // if key present => update
62
+ // Update existing key's value if present
63
+ for (Node node : nodes ) {
33
64
if (node .key .equals (key )) {
34
65
node .value = value ;
35
66
return ;
36
67
}
37
68
}
38
69
39
- // key is not present => insert
70
+ // Insert new key-value pair
40
71
nodes .add (new Node (key , value ));
41
72
size ++;
42
73
43
- if ((float ) size / buckets .length > lf ) {
74
+ // Check if rehashing is needed
75
+ if ((float ) size / buckets .length > loadFactorThreshold ) {
44
76
reHash ();
45
77
}
46
78
}
47
79
48
- // tells which bucket to go to
80
+ /**
81
+ * Returns the index of the bucket in which the key would be stored.
82
+ *
83
+ * @param key the key whose bucket index is to be computed
84
+ * @return the bucket index
85
+ */
49
86
private int hashFunction (K key ) {
50
87
return Math .floorMod (key .hashCode (), buckets .length );
51
88
}
52
89
90
+ /**
91
+ * Rehashes the map by doubling the number of buckets and re-inserting all entries.
92
+ */
53
93
private void reHash () {
54
94
System .out .println ("Rehashing!" );
55
- LinkedList <Node >[] old = buckets ;
56
- initBuckets (old .length * 2 );
95
+ LinkedList <Node >[] oldBuckets = buckets ;
96
+ initBuckets (oldBuckets .length * 2 );
57
97
this .size = 0 ;
58
98
59
- for (LinkedList <Node > nodes : old ) {
99
+ for (LinkedList <Node > nodes : oldBuckets ) {
60
100
for (Node node : nodes ) {
61
101
put (node .key , node .value );
62
102
}
63
103
}
64
104
}
65
105
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
+ */
66
111
public void remove (K key ) {
67
112
int bucketIndex = hashFunction (key );
68
113
LinkedList <Node > nodes = buckets [bucketIndex ];
@@ -74,14 +119,28 @@ public void remove(K key) {
74
119
break ;
75
120
}
76
121
}
77
- nodes .remove (target );
78
- size --;
122
+
123
+ if (target != null ) {
124
+ nodes .remove (target );
125
+ size --;
126
+ }
79
127
}
80
128
129
+ /**
130
+ * Returns the number of key-value pairs in this map.
131
+ *
132
+ * @return the number of key-value pairs
133
+ */
81
134
public int size () {
82
135
return this .size ;
83
136
}
84
137
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
+ */
85
144
public V get (K key ) {
86
145
int bucketIndex = hashFunction (key );
87
146
LinkedList <Node > nodes = buckets [bucketIndex ];
@@ -96,7 +155,6 @@ public V get(K key) {
96
155
@ Override
97
156
public String toString () {
98
157
StringBuilder builder = new StringBuilder ();
99
-
100
158
builder .append ("{" );
101
159
for (LinkedList <Node > nodes : buckets ) {
102
160
for (Node node : nodes ) {
@@ -106,19 +164,37 @@ public String toString() {
106
164
builder .append (", " );
107
165
}
108
166
}
167
+ // Remove trailing comma and space
168
+ if (builder .length () > 1 ) {
169
+ builder .setLength (builder .length () - 2 );
170
+ }
109
171
builder .append ("}" );
110
172
return builder .toString ();
111
173
}
112
174
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
+ */
113
181
public boolean containsKey (K key ) {
114
182
return get (key ) != null ;
115
183
}
116
184
185
+ /**
186
+ * A private class representing a key-value pair (node) in the hash map.
187
+ */
117
188
public class Node {
118
-
119
189
K key ;
120
190
V value ;
121
191
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
+ */
122
198
public Node (K key , V value ) {
123
199
this .key = key ;
124
200
this .value = value ;
0 commit comments