1
+ import java .util .ArrayList ;
2
+
3
+ public class MyHashMap <K , V > implements MyMap <K , V > {
4
+ // Define the default hash-table size. Must be power of 2
5
+ private static int DEFAULT_INITIAL_CAPACITY = 4 ;
6
+
7
+ // Define the maximum hash-table size. 1 << 30 is same as 2 ^ 30
8
+ private static int MAXIMUM_CAPACITY = 1 << 30 ;
9
+
10
+ // Current hash-table capacity. Capacity is a power of 2
11
+ private int capacity ;
12
+
13
+ // Define default load factor
14
+ private static float DEFAULT_MAX_LOAD_FACTOR = 0.5f ;
15
+
16
+ // Specify a load factor used in the hash table
17
+ private float loadFactorThreshold ;
18
+
19
+ // The number of entries in the map
20
+ private int size = 0 ;
21
+
22
+ // Hash table is an ArrayList
23
+ private ArrayList <MyMap .Entry <K , V >> table ;
24
+
25
+ /** Construct a map with the default capacity and load factor */
26
+ public MyHashMap () {
27
+ this (DEFAULT_INITIAL_CAPACITY , DEFAULT_MAX_LOAD_FACTOR );
28
+ }
29
+
30
+ /** Construct a map with the specified initial capacity and
31
+ * default load factor */
32
+ public MyHashMap (int initialCapacity ) {
33
+ this (initialCapacity , DEFAULT_MAX_LOAD_FACTOR );
34
+ }
35
+
36
+ /** Construct a map with the specified initial capacity
37
+ * and load factor */
38
+ public MyHashMap (int initialCapacity , float loadFactorThreshold ) {
39
+ if (initialCapacity > MAXIMUM_CAPACITY )
40
+ this .capacity = MAXIMUM_CAPACITY ;
41
+ else
42
+ this .capacity = trimToPowerOf2 (initialCapacity );
43
+
44
+ this .loadFactorThreshold = loadFactorThreshold ;
45
+ table = new ArrayList <>();
46
+ for (int i = 0 ; i < capacity ; i ++) {
47
+ table .add (null );
48
+ }
49
+ }
50
+
51
+ @ Override /** Remove all the entries from this map */
52
+ public void clear () {
53
+ size = 0 ;
54
+ removeEntries ();
55
+ }
56
+
57
+ @ Override /** Return true if the specified key is in the map */
58
+ public boolean containsKey (K key ) {
59
+ if (get (key ) != null )
60
+ return true ;
61
+ else
62
+ return false ;
63
+ }
64
+
65
+ @ Override /** Return true if this map contains the value */
66
+ public boolean containsValue (V value ) {
67
+ for (Entry <K , V > entry : table ) {
68
+ if (entry != null && entry .getValue () == value ) {
69
+ return true ;
70
+ }
71
+ }
72
+
73
+ return false ;
74
+ }
75
+
76
+ @ Override /** Return a set of entries in the map */
77
+ public java .util .Set <Entry <K , V >> entrySet () {
78
+ java .util .Set <Entry <K , V >> set = new java .util .HashSet <>();
79
+
80
+ for (Entry <K , V > entry : table ) {
81
+ if (entry != null )
82
+ set .add (entry );
83
+ }
84
+
85
+ return set ;
86
+ }
87
+
88
+ @ Override /** Return the value that matched the specified key */
89
+ public V get (K key ) {
90
+ int index = hash (key .hashCode ());
91
+ int i = index - 1 ;
92
+
93
+ while (i != index && (table .get (index ) == null ||
94
+ table .get (index ).getKey () != key )) {
95
+ index ++;
96
+ index %= capacity ;
97
+ }
98
+
99
+ if (table .get (index ).getKey () == key ) {
100
+ return table .get (index ).getValue ();
101
+ }
102
+
103
+ return null ;
104
+ }
105
+
106
+ @ Override /** Return a set of values that match the key in the map */
107
+ public java .util .Set <V > getAll (K key ) {
108
+ java .util .Set <V > set = new java .util .HashSet <>();
109
+ int index = hash (key .hashCode ());
110
+ int i = index - 1 ;
111
+
112
+ while (i != index ) {
113
+ if (table .get (index ) != null && table .get (index ).getKey () == key ) {
114
+ set .add (table .get (index ).getValue ());
115
+ }
116
+ index ++;
117
+ index %= capacity ;
118
+ }
119
+
120
+ return set ;
121
+ }
122
+
123
+ @ Override /** Return true if this map contains no entries */
124
+ public boolean isEmpty () {
125
+ return size == 0 ;
126
+ }
127
+
128
+ @ Override /** Return a set consisting of the keys in this map */
129
+ public java .util .Set <K > keySet () {
130
+ java .util .Set <K > set = new java .util .HashSet <>();
131
+
132
+ for (Entry <K , V > entry : table ) {
133
+ if (entry != null )
134
+ set .add (entry .getKey ());
135
+ }
136
+
137
+ return set ;
138
+ }
139
+
140
+ @ Override /** Add an entry (key, value) into the map */
141
+ public V put (K key , V value ) {
142
+ int index = hash (key .hashCode ());
143
+
144
+ while (table .get (index ) != null ) {
145
+ index ++;
146
+ index %= capacity ;
147
+ }
148
+
149
+ if (size >= capacity * loadFactorThreshold ) {
150
+ if (capacity == MAXIMUM_CAPACITY ) {
151
+ throw new RuntimeException ("Exceeding maximum capacity" );
152
+ }
153
+ rehash ();
154
+ }
155
+
156
+ // Add a new entry (key, value) to hash table
157
+ table .set (index , new MyMap .Entry <K , V >(key , value ));
158
+
159
+ size ++; // Increase size
160
+
161
+ return value ;
162
+ }
163
+
164
+ @ Override /** Remove the entry for the specified key */
165
+ public void remove (K key ) {
166
+ int index = hash (key .hashCode ());
167
+ int i = index - 1 ;
168
+
169
+ while (i != index && (table .get (index ) == null ||
170
+ table .get (index ).getKey () != key )) {
171
+ index ++;
172
+ index %= capacity ;
173
+ }
174
+
175
+ if (table .get (index ).getKey () == key ) {
176
+ table .remove (index );
177
+ }
178
+ }
179
+
180
+ @ Override /** Return the number of entries in this map */
181
+ public int size () {
182
+ return size ;
183
+ }
184
+
185
+ @ Override /** Return a set consisting of all the values in this map */
186
+ public java .util .Set <V > values () {
187
+ java .util .Set <V > set = new java .util .HashSet <>();
188
+
189
+ for (Entry <K , V > entry : table ) {
190
+ if (entry != null ) {
191
+ set .add (entry .getValue ());
192
+ }
193
+ }
194
+
195
+ return set ;
196
+ }
197
+
198
+ /** Hash function */
199
+ private int hash (int hashCode ) {
200
+ return supplementalHash (hashCode ) & (capacity - 1 );
201
+ }
202
+
203
+ /** Ensure the hashing is evenly distributed */
204
+ private int supplementalHash (int h ) {
205
+ h ^= (h >>> 20 ) ^ (h >>> 12 );
206
+ return h ^ (h >>> 7 ) ^ (h >>> 4 );
207
+ }
208
+
209
+ /** Return a power of 2 for initialCapacity */
210
+ private int trimToPowerOf2 (int initialcapacity ) {
211
+ int capacity = 1 ;
212
+ while (capacity < initialcapacity ) {
213
+ capacity <<= 1 ;
214
+ }
215
+
216
+ return capacity ;
217
+
218
+ }
219
+
220
+ /** Remove all entries from map */
221
+ private void removeEntries () {
222
+ table .clear ();
223
+ }
224
+
225
+ /** Rehash the map */
226
+ private void rehash () {
227
+ capacity <<= 1 ; // Same as *= 2. <= is more efficient
228
+ for (int i = size + 1 ; i < capacity ; i ++) {
229
+ table .add (null );
230
+ }
231
+ }
232
+
233
+ @ Override
234
+ public String toString () {
235
+ StringBuilder builder = new StringBuilder ("[" );
236
+
237
+ for (Entry <K , V > entry : table ) {
238
+ if (entry != null && size > 0 ) {
239
+ builder .append (entry );
240
+ }
241
+ }
242
+
243
+ builder .append ("]" );
244
+ return builder .toString ();
245
+ }
246
+ }
0 commit comments