/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package java.util; import java.io.Serializable; import java.util.AbstractSequentialList; import java.util.Collection; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.Queue; /** * Linked list implementation. <a * href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/LinkedList.html">[Sun docs]</a> * * @param <E> element type. */ public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Queue<E>, Deque<E>, Serializable { /* * This implementation uses a doubly-linked circular list with a header node. * * TODO(jat): add more efficient subList implementation. */ /** * Implementation of ListIterator for linked lists. */ private final class ListIteratorImpl implements ListIterator<E> { /** * The index to the current position. */ protected int currentIndex; /** * Current node, to be returned from next. */ protected Node<E> currentNode; /** * The last node returned from next/previous, or null if deleted or never called. */ protected Node<E> lastNode = null; /** * @param index from the beginning of the list (0 = first node) * @param startNode the initial current node */ public ListIteratorImpl(int index, Node<E> startNode) { currentNode = startNode; currentIndex = index; } public void add(E o) { addBefore(o, currentNode); ++currentIndex; lastNode = null; } public boolean hasNext() { return currentNode != header; } public boolean hasPrevious() { return currentNode.prev != header; } public E next() { if (!hasNext()) { throw new NoSuchElementException(); } lastNode = currentNode; currentNode = currentNode.next; ++currentIndex; return lastNode.value; } public int nextIndex() { return currentIndex; } public E previous() { if (!hasPrevious()) { throw new NoSuchElementException(); } lastNode = currentNode = currentNode.prev; --currentIndex; return lastNode.value; } public int previousIndex() { return currentIndex - 1; } public void remove() { verifyCurrentElement(); if (currentNode == lastNode) { // We just did a previous(). currentNode = lastNode.next; } else { // We just did a next(). --currentIndex; } lastNode.remove(); lastNode = null; --size; } public void set(E o) { verifyCurrentElement(); lastNode.value = o; } protected void verifyCurrentElement() { if (lastNode == null) { throw new IllegalStateException(); } } } /** * Internal class representing a doubly-linked list node. * * @param <E> element type */ private static class Node<E> { public Node<E> next; public Node<E> prev; public E value; public Node() { next = prev = this; } public Node(E value) { this.value = value; } /** * Construct a node containing a value and add it before the specified node. * * @param value * @param nextNode */ public Node(E value, Node<E> nextNode) { this(value); this.next = nextNode; this.prev = nextNode.prev; nextNode.prev.next = this; nextNode.prev = this; } /** * Remove this node from any list it is in, leaving it with circular references to itself. */ public void remove() { this.next.prev = this.prev; this.prev.next = this.next; this.next = this.prev = this; } } /** * Ensures that RPC will consider type parameter E to be exposed. It will be pruned by dead code * elimination. */ @SuppressWarnings("unused") private E exposeElement; /** * Header node - header.next is the first element of the list, and header.prev is the last element * of the list. If the list is empty, the header node will point to itself. */ private Node<E> header; /** * Number of nodes currently present in the list. */ private int size; public LinkedList() { clear(); } public LinkedList(Collection<? extends E> c) { this(); addAll(c); } @Override public boolean add(E o) { addLast(o); return true; } public void addFirst(E o) { new Node<E>(o, header.next); ++size; } public void addLast(E o) { new Node<E>(o, header); ++size; } @Override public void clear() { header = new Node<E>(); size = 0; } public E element() { return getFirst(); } public E getFirst() { throwEmptyException(); return header.next.value; } public E getLast() { throwEmptyException(); return header.prev.value; } /** * @since 1.6 */ public Iterator<E> descendingIterator() { return new DescendingIterator(header); } /** Adapter to provide descending iterators via ListItr.previous */ private class DescendingIterator implements Iterator<E> { final ListIteratorImpl itr; public DescendingIterator(Node<E> node) { itr = new ListIteratorImpl(size(), node); } public boolean hasNext() { return itr.hasPrevious(); } public E next() { return itr.previous(); } public void remove() { itr.remove(); } } @Override public ListIterator<E> listIterator(final int index) { if (index < 0 || index > size) { throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); } Node<E> node; // start from the nearest end of the list if (index >= size >> 1) { node = header; for (int i = size; i > index; --i) { node = node.prev; } } else { node = header.next; for (int i = 0; i < index; ++i) { node = node.next; } } return new ListIteratorImpl(index, node); } public boolean offer(E o) { return add(o); } public E peek() { if (size == 0) { return null; } else { return getFirst(); } } public E poll() { if (size == 0) { return null; } else { return removeFirst(); } } public E remove() { return removeFirst(); } public E removeFirst() { throwEmptyException(); --size; Node<E> node = header.next; node.remove(); return node.value; } public E removeLast() { throwEmptyException(); --size; Node<E> node = header.prev; node.remove(); return node.value; } @Override public int size() { return size; } private void addBefore(E o, Node<E> target) { new Node<E>(o, target); ++size; } /** * Throw an exception if the list is empty. */ private void throwEmptyException() { if (size == 0) { throw new NoSuchElementException(); } } /** * Inserts the specified element at the front of this deque. * * @param e the element to add * @return <tt>true</tt> (as specified by {@link Deque#offerFirst}) * @throws NullPointerException if the specified element is null */ public boolean offerFirst(E e) { addFirst(e); return true; } /** * Inserts the specified element at the end of this deque. * * @param e the element to add * @return <tt>true</tt> (as specified by {@link Deque#offerLast}) * @throws NullPointerException if the specified element is null */ public boolean offerLast(E e) { addLast(e); return true; } public E pollFirst() { return poll(); } public E pollLast() { return removeLast(); } public E peekFirst() { return peek(); } public E peekLast() { return peekLast(); } /** * Removes the first occurrence of the specified element in this deque (when traversing the deque * from head to tail). If the deque does not contain the element, it is unchanged. More formally, * removes the first element <tt>e</tt> such that <tt>o.equals(e)</tt> (if such an element * exists). Returns <tt>true</tt> if this deque contained the specified element (or equivalently, * if this deque changed as a result of the call). * * @param o element to be removed from this deque, if present * @return <tt>true</tt> if the deque contained the specified element */ public boolean removeFirstOccurrence(Object o) { if (o == null) return false; Iterator<E> iter = iterator(); while (iter.hasNext()) { E next = iter.next(); if (o.equals(next)) { iter.remove(); return true; } } return false; } /** * Removes the last occurrence of the specified element in this deque (when traversing the deque * from head to tail). If the deque does not contain the element, it is unchanged. More formally, * removes the last element <tt>e</tt> such that <tt>o.equals(e)</tt> (if such an element exists). * Returns <tt>true</tt> if this deque contained the specified element (or equivalently, if this * deque changed as a result of the call). * * @param o element to be removed from this deque, if present * @return <tt>true</tt> if the deque contained the specified element */ public boolean removeLastOccurrence(Object o) { if (o == null) return false; Iterator<E> iter = descendingIterator(); while (iter.hasNext()) { E next = iter.next(); if (o.equals(next)) { iter.remove(); return true; } } return false; } /** * Pushes an element onto the stack represented by this deque. In other words, inserts the element * at the front of this deque. * * <p> * This method is equivalent to {@link #addFirst}. * * @param e the element to push * @throws NullPointerException if the specified element is null */ public void push(E e) { addFirst(e); } /** * Pops an element from the stack represented by this deque. In other words, removes and returns * the first element of this deque. * * <p> * This method is equivalent to {@link #removeFirst()}. * * @return the element at the front of this deque (which is the top of the stack represented by * this deque) * @throws NoSuchElementException {@inheritDoc} */ public E pop() { return removeFirst(); } }