-
Notifications
You must be signed in to change notification settings - Fork 1.5k
implement custom hashmap class #1604
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,123 @@ | ||
package core.basesyntax; | ||
|
||
import java.util.Objects; | ||
|
||
public class MyHashMap<K, V> implements MyMap<K, V> { | ||
private static final int INITIAL_CAPACITY = 16; | ||
private static final float LOAD_FACTOR = 0.75f; | ||
private int capacity = INITIAL_CAPACITY; | ||
private int size = 0; | ||
private Node<K, V>[] elements = new Node[capacity]; | ||
|
||
public MyHashMap() { | ||
} | ||
|
||
@Override | ||
public void put(K key, V value) { | ||
int hash = this.hash(key); | ||
int position = hash % this.capacity; | ||
Node<K, V> currentNode = this.getNode(key); | ||
|
||
if (currentNode == null) { | ||
this.elements[position] = new Node<>(hash, key, value, null); | ||
} else { | ||
Node<K, V> lastNode = null; | ||
|
||
while (currentNode != null) { | ||
if (Objects.equals(key, currentNode.key)) { | ||
currentNode.value = value; | ||
return; | ||
} | ||
|
||
lastNode = currentNode; | ||
currentNode = currentNode.next; | ||
} | ||
|
||
lastNode.next = new Node<>(hash, key, value, null); | ||
} | ||
|
||
if (++this.size > (int)(capacity * LOAD_FACTOR)) { | ||
this.resize(); | ||
} | ||
} | ||
|
||
@Override | ||
public V getValue(K key) { | ||
return null; | ||
Node<K, V> currentNode = this.getNode(key); | ||
|
||
if (currentNode == null) { | ||
return null; | ||
} | ||
|
||
while (currentNode != null) { | ||
if (Objects.equals(currentNode.key, key)) { | ||
break; | ||
} | ||
|
||
currentNode = currentNode.next; | ||
} | ||
|
||
return currentNode == null ? null : currentNode.value; | ||
} | ||
|
||
@Override | ||
public int getSize() { | ||
return 0; | ||
return this.size; | ||
} | ||
|
||
private void resize() { | ||
int oldCap = this.capacity; | ||
int newCap = this.capacity << 1; | ||
Node<K, V>[] newElements = new Node[newCap]; | ||
|
||
for (int i = 0; i < oldCap; i++) { | ||
Node<K, V> node = this.elements[i]; | ||
|
||
while (node != null) { | ||
int newPosition = node.hash % newCap; | ||
Node<K, V> newNode = new Node<>(node.hash, node.key, node.value, null); | ||
|
||
if (newElements[newPosition] == null) { | ||
newElements[newPosition] = newNode; | ||
} else { | ||
Node<K, V> currentNode = newElements[newPosition]; | ||
Node<K, V> lastNode = null; | ||
|
||
while (currentNode != null) { | ||
lastNode = currentNode; | ||
currentNode = currentNode.next; | ||
} | ||
|
||
lastNode.next = newNode; | ||
} | ||
|
||
node = node.next; | ||
} | ||
Comment on lines
+76
to
+95
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation of
A much more efficient approach is to prepend the old nodes to the new buckets. This avoids both creating new objects and traversing lists. Consider this logic inside your Node<K, V> nextNode = node.next; // Save the next node from the old chain
int newPosition = node.hash % newCap;
node.next = newElements[newPosition]; // Link the current node to the start of the new chain
newElements[newPosition] = node; // The current node becomes the new head
node = nextNode; // Move to the next node in the old chain |
||
} | ||
|
||
this.elements = newElements; | ||
this.capacity = newCap; | ||
} | ||
|
||
private int hash(K key) { | ||
return key == null ? 0 : key.hashCode() & Integer.MAX_VALUE; | ||
} | ||
|
||
private Node<K, V> getNode(K key) { | ||
return this.elements[this.hash(key) % this.capacity]; | ||
} | ||
|
||
private static class Node<K, V> { | ||
private final int hash; | ||
private final K key; | ||
private V value; | ||
private Node<K, V> next; | ||
|
||
private Node(int hash, K key, V value, Node<K, V> node) { | ||
this.hash = hash; | ||
this.key = key; | ||
this.value = value; | ||
this.next = node; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the
put
method, you calculate thehash
andposition
on lines 17 and 18. However, thegetNode(key)
call on this line recalculates the same values internally.To avoid this redundant work, you can directly access the head of the bucket using the
position
you already calculated, like this:Node<K, V> currentNode = this.elements[position];