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
12
30
31
+ /**
32
+ * Constructs a new empty hash map with an initial capacity of 16.
33
+ */
13
34
public GenericHashMapUsingArray () {
14
35
initBuckets (16 );
15
36
size = 0 ;
16
37
}
17
38
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
+ */
22
44
private void initBuckets (int n ) {
23
45
buckets = new LinkedList [n ];
24
46
for (int i = 0 ; i < buckets .length ; i ++) {
25
47
buckets [i ] = new LinkedList <>();
26
48
}
27
49
}
28
50
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
+ */
29
58
public void put (K key , V value ) {
30
59
int bucketIndex = hashFunction (key );
31
60
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 ) {
33
63
if (node .key .equals (key )) {
34
64
node .value = value ;
35
65
return ;
36
66
}
37
67
}
38
68
39
- // key is not present => insert
69
+ // Insert new key-value pair
40
70
nodes .add (new Node (key , value ));
41
71
size ++;
42
72
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 ) {
44
77
reHash ();
45
78
}
46
79
}
47
80
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
+ */
49
87
private int hashFunction (K key ) {
50
88
return Math .floorMod (key .hashCode (), buckets .length );
51
89
}
52
90
91
+ /**
92
+ * Rehashes the map by doubling the number of buckets and re-inserting all entries.
93
+ */
53
94
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 );
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