E.g: if a linked list contains 2->3->1->3->4 then the result should be 2->3->1->4. Notice that 3 has been eliminated.
This code is attributed to GeeksforGeeks. I'm looking for code-review, optimizations and best practices.
public class EliminateDuplicateUnsortedLL<T> {
private Node<T> first;
private Node<T> last;
public EliminateDuplicateUnsortedLL(List<T> items) {
for (T item : items) {
add(item);
}
}
public void add(T item) {
Node<T> node = new Node<>(item);
if (first == null) {
first = last = node;
} else {
last.next = node;
last = node;
}
}
private static class Node<T> {
private Node<T> next;
private T item;
Node(T item) {
this.item = item;
}
}
public void eliminateDuplicates() {
final Set<T> set = new HashSet<T>();
Node<T> prev = null;
for (Node<T> x = first; x != null; x = x.next) {
if (set.contains(x.item)) {
prev.next = x.next;
} else {
set.add(x.item);
prev = x;
}
}
last = prev;
}
public List<T> toList() {
final List<T> list = new ArrayList<>();
for (Node<T> x = first; x != null; x = x.next) {
list.add(x.item);
}
return list;
}
@Override
public int hashCode() {
int hashCode = 1;
for (Node<T> x = first; x != null; x = x.next)
hashCode = 31*hashCode + x.hashCode();
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EliminateDuplicateUnsortedLL<T> other = (EliminateDuplicateUnsortedLL<T>) obj;
Node<T> currentListNode = first;
Node<T> otherListNode = other.first;
while (currentListNode != null && otherListNode != null) {
if (currentListNode.item != otherListNode.item) return false;
currentListNode = currentListNode.next;
otherListNode = otherListNode.next;
}
return currentListNode == null && otherListNode == null;
}
}
Unit tests:
public class EliminateDuplicateUnsortedLLTest {
@Test
public void test1() {
EliminateDuplicateUnsortedLL<Integer> edu1 = new EliminateDuplicateUnsortedLL<Integer>(Arrays.asList(1, 2, 3, 4, 5, 4, 3, 7));
edu1.eliminateDuplicates();
EliminateDuplicateUnsortedLL<Integer> eduExpected1 = new EliminateDuplicateUnsortedLL<Integer>(Arrays.asList(1, 2, 3, 4, 5, 7));
assertEquals(eduExpected1, edu1);
}
@Test
public void test2() {
EliminateDuplicateUnsortedLL<Integer> edu2 = new EliminateDuplicateUnsortedLL<Integer>(Arrays.asList(7, 2, 5, 10, 4, 2, 9, 10));
edu2.eliminateDuplicates();
EliminateDuplicateUnsortedLL<Integer> eduExpected2 = new EliminateDuplicateUnsortedLL<Integer>(Arrays.asList(7, 2, 5, 10, 4, 9));
assertEquals(eduExpected2, edu2);
}
@Test
public void testAllDuplicates() {
EliminateDuplicateUnsortedLL<Integer> edu3 = new EliminateDuplicateUnsortedLL<Integer>(Arrays.asList(2, 2, 2, 2, 2));
edu3.eliminateDuplicates();
EliminateDuplicateUnsortedLL<Integer> eduExpected3 = new EliminateDuplicateUnsortedLL<Integer>(Arrays.asList(2));
assertEquals(eduExpected3, edu3);
}
}