1+ import java .util .LinkedList ;
2+
3+ public class MyHashMap <K ,V >implements MyMap <K ,V > {
4+ // Define the default hash-table size. Must be a 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.75f ;
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 array with each cell being a linked list
23+ LinkedList <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 LinkedList [capacity ];
46+ }
47+
48+ @ Override /** Remove all of the entries from this map */
49+ public void clear () {
50+ size =0 ;
51+ removeEntries ();
52+ }
53+
54+ @ Override /** Return true if the specified key is in the map */
55+ public boolean containsKey (K key ) {
56+ if (get (key ) !=null )
57+ return true ;
58+ else
59+ return false ;
60+ }
61+
62+ @ Override /** Return true if this map contains the value */
63+ public boolean containsValue (V value ) {
64+ for (int i =0 ;i <capacity ;i ++) {
65+ if (table [i ] !=null ) {
66+ LinkedList <Entry <K ,V >>bucket =table [i ];
67+ for (Entry <K ,V >entry :bucket )
68+ if (entry .getValue ().equals (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 <MyMap .Entry <K ,V >>entrySet () {
78+ java .util .Set <MyMap .Entry <K ,V >>set =
79+ new java .util .HashSet <>();
80+
81+ for (int i =0 ;i <capacity ;i ++) {
82+ if (table [i ] !=null ) {
83+ LinkedList <Entry <K ,V >>bucket =table [i ];
84+ for (Entry <K ,V >entry :bucket )
85+ set .add (entry );
86+ }
87+ }
88+
89+ return set ;
90+ }
91+
92+ @ Override /** Return the value that matches the specified key */
93+ public V get (K key ) {
94+ int bucketIndex =hash (key .hashCode ());
95+ if (table [bucketIndex ] !=null ) {
96+ LinkedList <Entry <K ,V >>bucket =table [bucketIndex ];
97+ for (Entry <K ,V >entry :bucket )
98+ if (entry .getKey ().equals (key ))
99+ return entry .getValue ();
100+ }
101+
102+ return null ;
103+ }
104+
105+ @ Override /** Return true if this map contains no entries */
106+ public boolean isEmpty () {
107+ return size ==0 ;
108+ }
109+
110+ @ Override /** Return a set consisting of the keys in this map */
111+ public java .util .Set <K >keySet () {
112+ java .util .Set <K >set =new java .util .HashSet <>();
113+
114+ for (int i =0 ;i <capacity ;i ++) {
115+ if (table [i ] !=null ) {
116+ LinkedList <Entry <K ,V >>bucket =table [i ];
117+ for (Entry <K ,V >entry :bucket ) {
118+ set .add (entry .getKey ());
119+ }
120+ }
121+ }
122+
123+ return set ;
124+ }
125+
126+ @ Override /** Add and entry (key, value) into the map */
127+ public V put (K key ,V value ) {
128+ if (get (key ) !=null ) {// The key is already in the map
129+ int bucketIndex =hash (key .hashCode ());
130+ LinkedList <Entry <K ,V >>bucket =table [bucketIndex ];
131+ for (Entry <K ,V >entry :bucket )
132+ if (entry .getKey ().equals (key )) {
133+ V oldValue =entry .getValue ();
134+ // Replace old value with new value
135+ entry .value =value ;
136+ // Return the old value for the key
137+ return oldValue ;
138+ }
139+ }
140+
141+ // Check load factor
142+ if (size >=capacity *loadFactorThreshold ) {
143+ if (capacity ==MAXIMUM_CAPACITY )
144+ throw new RuntimeException ("Exceeding maximum capacity" );
145+
146+ rehash ();
147+ }
148+
149+ int bucketIndex =hash (key .hashCode ());
150+
151+ // Create a linked list for the bucket if not already created
152+ if (table [bucketIndex ] ==null ) {
153+ table [bucketIndex ] =new LinkedList <Entry <K ,V >>();
154+ }
155+
156+ // Add a new entry (key, value) to hashtable[index]
157+ table [bucketIndex ].add (new MyMap .Entry <K ,V >(key ,value ));
158+
159+ size ++;// Increase size
160+
161+ return value ;
162+ }
163+
164+ @ Override /** Remove the entries for the specifie key */
165+ public void remove (K key ) {
166+ int bucketIndex =hash (key .hashCode ());
167+
168+ // Remove the first entry that matches the key from a bucket
169+ if (table [bucketIndex ] !=null ) {
170+ LinkedList <Entry <K ,V >>bucket =table [bucketIndex ];
171+ for (Entry <K ,V >entry :bucket )
172+ if (entry .getKey ().equals (key )) {
173+ bucket .remove (entry );
174+ size --;// Decrease size
175+ break ;// Remove just one entry that matches the key
176+ }
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 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 (int i =0 ;i <capacity ;i ++) {
190+ if (table [i ] !=null ) {
191+ LinkedList <Entry <K ,V >>bucket =table [i ];
192+ for (Entry <K ,V >entry :bucket ) {
193+ set .add (entry .getValue ());
194+ }
195+ }
196+ }
197+
198+ return set ;
199+ }
200+
201+ /** Hash function */
202+ private int hash (int hashCode ) {
203+ return supplementalHash (hashCode ) & (capacity -1 );
204+ }
205+
206+ /** Ensure the hashing is evenly distributed */
207+ private int supplementalHash (int h ) {
208+ h ^= (h >>>20 ) ^ (h >>>12 );
209+ return h ^ (h >>>7 ) ^ (h >>>4 );
210+ }
211+
212+ /** Return a power of 2 for initialCapacity */
213+ private int trimToPowerOf2 (int initialCapacity ) {
214+ int capacity =1 ;
215+ while (capacity <initialCapacity ) {
216+ capacity <<=1 ;// Same as capacity *= 2. <= is more efficient
217+ }
218+
219+ return capacity ;
220+ }
221+
222+ /** Remove all entries from each bucket */
223+ private void removeEntries () {
224+ for (int i =0 ;i <capacity ;i ++) {
225+ if (table [i ] !=null ) {
226+ table [i ].clear ();
227+ }
228+ }
229+ }
230+
231+ /** Rehash the map */
232+ private void rehash () {
233+ java .util .Set <MyMap .Entry <K ,V >>set =entrySet ();// Get entries
234+ capacity <<=1 ;// Same as capacity *= 2. <= is more efficient
235+ table =new LinkedList [capacity ];// Crate a new hash table
236+ size =0 ;
237+
238+ for (Entry <K ,V >entry :set ) {
239+ put (entry .getKey (),entry .getValue ());// Store to new table
240+ }
241+ }
242+
243+ @ Override /** Return a string representation for this map */
244+ public String toString () {
245+ StringBuilder builder =new StringBuilder ("[" );
246+ for (int i =0 ;i <capacity ;i ++) {
247+ if (table [i ] !=null &&table [i ].size () >0 )
248+ for (Entry <K ,V >entry :table [i ]) {
249+ builder .append (entry );
250+ }
251+ }
252+
253+ builder .append ("]" );
254+ return builder .toString ();
255+ }
256+ }