As our second main functionality, we will implement the ability to insert values
into a MyHashMap
based on their corresponding key
.
However, before we implement such a put
method, we need to create a couple more helper methods that will simplify our implementation.
Since we are using SimpleEntry<K, V>
objects to represent a key/value
pair, we want to insert a SimpleEntry<K, V>
object in our hashtable
. For this, we will implement a private insert
helper method that takes a SimpleEntry<K, V> entry
as a parameter and behaves as follows:
Gets the key
for the entry
using its getKey()
method and calculates the appropriate index
as in Step 1 of the find
method from Part 2 of the lab.
Gets the appropriate LinkedList
from the hashtable
using the index
calculated in Step 1.
Adds the given entry
to the LinkedList
found in Step 2.
Here, we assume that the key
of the given SimpleEntry<K, V>
is not already in the hashtable
.
As we insert more and more key/value
pairs into our hashtable
, we increase the likelihood that two key
s collide by having the same index
into the hashtable
’s bucket array based on their (different) hashCode
s. Since we are using chaining to handle collisions, the runtime of our methods will increase as the number of collisions also increases.
To minimize the risk of collisions, we will resize the hashtable
once the size of the MyHashMap
reaches a predetermined percentage of the number of buckets in the hashtable
’s bucket array. Implement a private resize
method that takes no parameters, returns nothing, and behaves as follows:
Save the old hashtable
as a different variable
Create a new array for the hashtable
instance variable using the provided createTable
method, passing in double the length
of the old hashtable
so that the size is at least doubled (n.b., it will actually be the next prime number after double the old length).
Iterate through every SimpleEntry<K, V>
in every LinkedList
in the old hashtable
and call put
to re-hash and re-insert the key/value
pairs.
In Java, inserting a new key/value
pair is accomplished through the method:
public V put(K key, V value)
If the key
was already in the MyHashMap
, then the method returns the previous value stored for that key
, else it returns null
. The pseudocode for this method is:
Use the find
method developed above to look up whether key
was already in the MyHashMap
If find
returns a SimpleEntry<K, V>
object because key
was already in the HashMap
, save the previous value from the SimpleEntry<K, V>
and change the value to the value
passed into the method using SimpleEntry
’s setValue(value)
method
If find
instead returned null
because key
was not already in the HashMap
, then we need to create a new SimpleEntry<K, V>
storing the given key
and value
that were arguments to the put
method. Call the insert
helper method described above, and increase the size
of the MyHashMap
since a new key
was inserted.
Next, check whether we need to resize the hashtable
so that we can minimize the risk of collisions. This should occur whenever the size
of the MyHashMap
is greater than LOAD_FACTOR
times the current length
of the hashtable
.
If the key
was already in the HashMap
, return the old value saved in Step 2. Otherwise, return null
Before moving on to the next part of the lab, we should create unit tests to verify our implementation so far and help us find and remove any bugs. As in previous labs, we can create a Java file that will contain our unit tests by right clicking anywhere in the MyHashMap.java
file and selecting “Source Action” from the right click menu. Then, select “Generate Tests”. Use the default name proposed by the IDE of MyHashMapTest
. Next, it will prompt you with what methods you want to create tests for.
Inside the newly created MyHashMapTest.java file, create a unit test verifying that the put
method works properly. As one strategy, you could:
MyHashMap<String, Integer>
instancevalue
for a new String key
and make sure that the put
method returns null
since the key
was newvalue
for an existing String key
and make sure that the put
method returns the previous value stored for that key
You can also now create unit tests for your get
method described in Part 2 of the lab, as well as the size
, isEmpty
, and clear
methods described in Part 1 of the lab.
Hint
Remember the Debugger in Visual Studio Code, which will allow you to inspect the values of variables as you debug your unit tests.
You might also want to temporarily make your find
, insert
, and resize
methods public
so that you can call them within your unit tests (since they does the majority of the work of the get
and put
methods).
Don’t forget to frequently save your progress to GitHub using the add
/commit
/push
commands with git.