import java.util.Iterator; public class NLinkedList implements Iterable { private NLinkedListNode head, tail; public NLinkedListNode getFirst(){ return this.head; } public NLinkedListNode getLast(){ return this.tail; } public NLinkedList(){ head = null; tail = null; } public void addFirst(E value){ this.addFirst(new NLinkedListNode(value)); } public void addFirst(NLinkedListNode node){ assert (head == null ? tail == null : false) : "Both head and tail must be null, or neither"; if(head == null){ head = tail = node; node.setNext(null); node.setPrevious(null); } else { node.addBefore(head); head = node; } } public void removeFirst(){ if(head != null){ NLinkedListNode nHead = head.getNext(); head.remove(); this.head = nHead; } } public void addLast(E value){ this.addLast(new NLinkedListNode(value)); } public void addLast(NLinkedListNode node){ assert (head == null ? tail == null : false) : "Both head and tail must be null, or neither"; if(tail == null){ head = tail = node; node.setNext(null); node.setPrevious(null); } else { node.addAfter(tail); tail = node; } } public void removeLast(){ if(tail != null){ NLinkedListNode nTail = tail.getPrevious(); tail.remove(); this.tail = nTail; } } public boolean isEmpty(){ return this.head == null; } public void clear(){ while(!this.isEmpty()) this.removeFirst(); } @Override public Iterator iterator() { return new Iterator() { NLinkedListNode current = getFirst(); boolean removed = false; @Override public boolean hasNext() { return current != null && current.getNext() != null; } @Override public E next() { removed = false; if(this.current != null) this.current = this.current.getNext(); return this.current != null ? this.current.getValue() : null; } @Override public void remove() { if(removed || this.current == null) return; removed = true; this.current.remove(); } }; } }