I am trying to implement my own LinkedHashMap using chaining strategy for deal with collisions. Below code snippet shows what I have tried so far.
CustomLinkedHashMap
public class CustomLinkedHashMap<K, V> {
private Entry<K, V>[] table;
private int capacity = 4;
private Entry<K, V> header;
private Entry<K, V> last;
@SuppressWarnings("unchecked")
public CustomLinkedHashMap() {
table = new Entry[capacity];
}
@SuppressWarnings("unchecked")
public boolean equals(Object that) {
if (!(that instanceof CustomLinkedHashMap)) {
return false;
}
CustomLinkedHashMap<K, V> other = (CustomLinkedHashMap<K, V>) that;
// if lists are empty
if (header == null) {
return other.header == null;
}
if (!header.equals(other.header)) {
return false;
}
// Just one element
if (header == last) {
return true;
}
if (!header.equals(other.last)) {
return false;
}
Entry<K, V> thisNode = header;
Entry<K, V> otherNode = other.header;
while (thisNode.next != last) {
thisNode = thisNode.next;
otherNode = otherNode.next;
if (!(thisNode.equals(otherNode))) {
return false;
}
}
return true;
}
public void put(K newKey, V data) {
if (newKey == null)
return; //nulls not allowed
int hash = hash(newKey);
Entry<K, V> newEntry = new Entry<K, V>(newKey, data, null);
maintainOrderAfterInsert(newEntry);
if (table[hash] == null) {
table[hash] = newEntry;
} else {
Entry<K, V> previous = null;
Entry<K, V> current = table[hash];
while (current != null) { // reached to the last entry of bucket.
if (current.key.equals(newKey)) {
if (previous == null) { //node has to be insert on first of bucket.
newEntry.next = current.next;
table[hash] = newEntry;
return;
} else {
newEntry.next = current.next;
previous.next = newEntry;
return;
}
}
previous = current;
current = current.next;
}
previous.next = newEntry;
}
}
public boolean isEmpty() {
return header == null;
}
public void clear() {
if (table != null && capacity > 0) {
header = null;
last = null;
capacity = 0;
}
}
public void printMap() {
Entry<K, V> currentEntry = header;
while (currentEntry != null) {
System.out.print("{" + currentEntry.key + "=" + currentEntry.value + "}" + " ");
currentEntry = currentEntry.after;
}
}
private int hash(K key) {
return Math.abs(key.hashCode()) % capacity;
}
static class Entry<K, V> {
K key;
V value;
Entry<K, V> next;
Entry<K, V> before, after;
public Entry(K key, V value, Entry<K, V> next) {
this.key = key;
this.value = value;
this.next = next;
}
@SuppressWarnings("unchecked")
public boolean equals(Object object) {
if (object == this)
return true;
if (object instanceof Entry) {
Entry<K, V> e = (Entry<K, V>) object;
if (Objects.equals(key, e.key) && Objects.equals(value, e.value)) {
return true;
}
}
return false;
}
}
}
CustomLinkedHashMap
class Full implementation here.
As for my implementation when I try equals
method it always returns me false
.
CustomLinkedHashMap<Integer, String> lhm = new CustomLinkedHashMap<>();
lhm.put(13, "John");
lhm.put(3, "Holmes");
lhm.put(19, "Jenifer");
CustomLinkedHashMap<Integer, String> lhm2 = new CustomLinkedHashMap<>();
lhm2.put(13, "John");
lhm2.put(3, "Holmes");
lhm2.put(19, "Jenifer");
System.out.println(lhm.equals(lhm2)); // Returns true when using java.util.LinkedHashMap
Any suggestions would be appreciable.
Your equals
for CustomLinkedHashMap
is way too complicated. All you really need is to check the entries (and their ordering):
@Override
public boolean equals(@Nullable Object thatObject) {
if (!(thatObject instanceof CustomLinkedHashMap)) {
return false;
}
CustomLinkedHashMap<?,?> thatMap =
(CustomLinkedHashMap<?,?>) thatObject;
return Arrays.equals(this.table, thatMap.table);
}
You also need a solid implementation for Entry
, which checks the key and value against another:
@Override
public boolean equals(@Nullable Object thatObject) {
if (!(thatObject instanceof Entry)) {
return false;
}
Entry<?,?> thatEntry = (Entry<?,?>) thatObject;
if (!Objects.equals(this.key, thatEntry.key)) {
return false;
}
return Objects.equals(this.value, thatEntry.value));
}