import java.util.NoSuchElementException; /** An implementation of a doubly linked list. */ public class LinkedList { private Node first; private Node last; /** Constructs an empty linked list. */ public LinkedList() { first = null; last = null; } /** Returns the first element in the linked list. @return the first element in the linked list */ public Object getFirst() { if (first == null) { throw new NoSuchElementException(); } return first.data; } /** Removes the first element in the linked list. @return the removed element */ public Object removeFirst() { if (first == null) { throw new NoSuchElementException(); } Object element = first.data; first = first.next; if (first == null) { last = null; } // List is now empty else { first.previous = null; } return element; } /** Adds an element to the front of the linked list. @param element the element to add */ public void addFirst(Object element) { Node newNode = new Node(); newNode.data = element; newNode.next = first; newNode.previous = null; if (first == null) { last = newNode; } else { first.previous = newNode; } first = newNode; } /** Returns the last element in the linked list. @return the last element in the linked list */ public Object getLast() { if (last == null) { throw new NoSuchElementException(); } return last.data; } /** Removes the last element in the linked list. @return the removed element */ public Object removeLast() { if (last == null) { throw new NoSuchElementException(); } Object element = last.data; last = last.previous; if (last == null) { first = null; } // List is now empty else { last.next = null; } return element; } /** Adds an element to the back of the linked list. @param element the element to add */ public void addLast(Object element) { Node newNode = new Node(); newNode.data = element; newNode.next = null; newNode.previous = last; if (last == null) { first = newNode; } else { last.next = newNode; } last = newNode; } /** Returns an iterator for iterating through this list. @return an iterator for iterating through this list */ public ListIterator listIterator() { return new LinkedListIterator(); } class Node { public Object data; public Node next; public Node previous; } class LinkedListIterator implements ListIterator { private Node position; private boolean isAfterNext; private boolean isAfterPrevious; /** Constructs an iterator that points to the front of the linked list. */ public LinkedListIterator() { position = null; isAfterNext = false; isAfterPrevious = false; } /** Moves the iterator past the next element. @return the traversed element */ public Object next() { if (!hasNext()) { throw new NoSuchElementException(); } isAfterNext = true; isAfterPrevious = false; if (position == null) { position = first; } else { position = position.next; } return position.data; } /** Tests if there is an element after the iterator position. @return true if there is an element after the iterator position */ public boolean hasNext() { if (position == null) { return first != null; } else { return position.next != null; } } /** Moves the iterator before the previous element. @return the traversed element */ public Object previous() { if (!hasPrevious()) { throw new NoSuchElementException(); } isAfterNext = false; isAfterPrevious = true; Object result = position.data; position = position.previous; return result; } /** Tests if there is an element before the iterator position. @return true if there is an element before the iterator position */ public boolean hasPrevious() { return position != null; } /** Adds an element before the iterator position and moves the iterator past the inserted element. @param element the element to add */ public void add(Object element) { if (position == null) { addFirst(element); position = first; } else if (position == last) { addLast(element); position = last; } else { Node newNode = new Node(); newNode.data = element; newNode.next = position.next; newNode.next.previous = newNode; position.next = newNode; newNode.previous = position; position = newNode; } isAfterNext = false; isAfterPrevious = false; } /** Removes the last traversed element. This method may only be called after a call to the next() method. */ public void remove() { Node positionToRemove = lastPosition(); if (positionToRemove == first) { removeFirst(); } else if (positionToRemove == last) { removeLast(); } else { positionToRemove.previous.next = positionToRemove.next; positionToRemove.next.previous = positionToRemove.previous; } if (isAfterNext) { position = position.previous; } isAfterNext = false; isAfterPrevious = false; } /** Sets the last traversed element to a different value. @param element the element to set */ public void set(Object element) { Node positionToSet = lastPosition(); positionToSet.data = element; } /** Returns the last node traversed by this iterator, or throws an IllegalStateException if there wasn't an immediately preceding call to next or previous. @return the last traversed node */ private Node lastPosition() { if (isAfterNext) { return position; } else if (isAfterPrevious) { if (position == null) { return first; } else { return position.next; } } else { throw new IllegalStateException(); } } } }