A simple linked List implementation : Your LinkedList « Collections « Java Tutorial






import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.NoSuchElementException;

/*
 * Copyright 2005 JBoss 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.
 */

/**
 * This is a simple linked linked implementation. Each node must implement
 * </code>LinkedListNode<code> so that it references the node before and after
 * it. This way a node can be removed without having to scan the list to find
 * it. This class does not provide an Iterator implementation as its designed
 * for efficiency and not genericity. There are a number of ways to iterate the
 * list.
 * 
 * Simple iterator:
 * 
 * <pre>
 * for (LinkedListNode node = list.getFirst(); node != null; node = node.getNext()) {
 * }
 * </pre>
 * 
 * Iterator that pops the first entry:
 * 
 * <pre>
 * for (LinkedListNode node = list.removeFirst(); node != null; node = list.removeFirst()) {
 * }
 * </pre>
 * 
 * 
 * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
 * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
 * 
 */
public class LinkedList implements Externalizable {
  private static final long serialVersionUID = 400L;

  private LinkedListNode firstNode;

  private LinkedListNode lastNode;

  private int size;

  private LinkedListIterator iterator;

  /**
   * Construct an empty <code>LinkedList</code>
   */
  public LinkedList() {
    this.iterator = new LinkedListIterator();
  }

  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    firstNode = (LinkedListNode) in.readObject();
    lastNode = (LinkedListNode) in.readObject();
    size = in.readInt();
    iterator = (LinkedListIterator) in.readObject();
  }

  public void writeExternal(ObjectOutput out) throws IOException {
    out.writeObject(firstNode);
    out.writeObject(lastNode);
    out.writeInt(size);
    out.writeObject(iterator);
  }

  /**
   * Add a <code>LinkedListNode</code> to the list. If the
   * <code>LinkedList</code> is empty then the first and last nodes are set to
   * the added node.
   * 
   * @param node
   *          The <code>LinkedListNode</code> to be added
   */
  public void add(final LinkedListNode node) {
    if (this.firstNode == null) {
      this.firstNode = node;
      this.lastNode = node;
    } else {
      this.lastNode.setNext(node);
      node.setPrevious(this.lastNode);
      this.lastNode = node;
    }
    this.size++;
  }

  /**
   * Removes a <code>LinkedListNode</code> from the list. This works by attach
   * the previous reference to the child reference. When the node to be removed
   * is the first node it calls <code>removeFirst()</code>. When the node to
   * be removed is the last node it calls <code>removeLast()</code>.
   * 
   * @param node
   *          The <code>LinkedListNode</code> to be removed.
   */
  public void remove(final LinkedListNode node) {
    if (this.firstNode == node) {
      removeFirst();
    } else if (this.lastNode == node) {
      removeLast();
    } else {
      node.getPrevious().setNext(node.getNext());
      (node.getNext()).setPrevious(node.getPrevious());
      this.size--;
      node.setPrevious(null);
      node.setNext(null);
    }
  }

  /**
   * Return the first node in the list
   * 
   * @return The first <code>LinkedListNode</code>.
   */
  public final LinkedListNode getFirst() {
    return this.firstNode;
  }

  /**
   * Return the last node in the list
   * 
   * @return The last <code>LinkedListNode</code>.
   */
  public final LinkedListNode getLast() {
    return this.lastNode;
  }

  /**
   * Remove the first node from the list. The next node then becomes the first
   * node. If this is the last node then both first and last node references are
   * set to null.
   * 
   * @return The first <code>LinkedListNode</code>.
   */
  public LinkedListNode removeFirst() {
    if (this.firstNode == null) {
      return null;
    }
    final LinkedListNode node = this.firstNode;
    this.firstNode = node.getNext();
    node.setNext(null);
    if (this.firstNode != null) {
      this.firstNode.setPrevious(null);
    } else {
      this.lastNode = null;
    }
    this.size--;
    return node;
  }

  public void insertAfter(final LinkedListNode existingNode, final LinkedListNode newNode) {
    if (newNode.getPrevious() != null || newNode.getNext() != null) {
      // do nothing if this node is already inserted somewhere
      return;
    }

    if (existingNode == null) {
      if (this.isEmpty()) {
        this.firstNode = newNode;
        this.lastNode = newNode;
      } else {
        // if existing node is null, then insert it as a first node
        final LinkedListNode node = this.firstNode;
        node.setPrevious(newNode);
        newNode.setNext(node);
        this.firstNode = newNode;
      }
    } else if (existingNode == this.lastNode) {
      existingNode.setNext(newNode);
      newNode.setPrevious(existingNode);
      this.lastNode = newNode;
    } else {
      (existingNode.getNext()).setPrevious(newNode);
      newNode.setNext(existingNode.getNext());
      existingNode.setNext(newNode);
      newNode.setPrevious(existingNode);
    }
    this.size++;
  }

  /**
   * Remove the last node from the list. The previous node then becomes the last
   * node. If this is the last node then both first and last node references are
   * set to null.
   * 
   * @return The first <code>LinkedListNode</code>.
   */
  public LinkedListNode removeLast() {
    if (this.lastNode == null) {
      return null;
    }
    final LinkedListNode node = this.lastNode;
    this.lastNode = node.getPrevious();
    node.setPrevious(null);
    if (this.lastNode != null) {
      this.lastNode.setNext(null);
    } else {
      this.firstNode = this.lastNode;
    }
    this.size--;
    return node;
  }

  /**
   * @return boolean value indicating the empty status of the list
   */
  public final boolean isEmpty() {
    return (this.firstNode == null);
  }

  /**
   * Iterates the list removing all the nodes until there are no more nodes to
   * remove.
   */
  public void clear() {
    while (removeFirst() != null) {
    }
  }

  /**
   * @return return size of the list as an int
   */
  public final int size() {
    return this.size;
  }

  public int hashCode() {
    final int PRIME = 31;
    int result = 1;
    for (LinkedListNode node = this.firstNode; node != null; node = node.getNext()) {
      result = PRIME * result + node.hashCode();
    }
    return result;
  }

  public boolean equals(final Object object) {
    if (object == this) {
      return true;
    }

    if (object == null || !(object instanceof LinkedList)) {
      return false;
    }

    final LinkedList other = (LinkedList) object;

    if (this.size() != other.size()) {
      return false;
    }

    for (LinkedListNode thisNode = this.firstNode, otherNode = other.firstNode; thisNode != null
        && otherNode != null; thisNode = thisNode.getNext(), otherNode = otherNode.getNext()) {
      if (!thisNode.equals(otherNode)) {
        return false;
      }
    }
    return true;
  }

  public Iterator iterator() {
    this.iterator.reset(this);
    return this.iterator;
  }

  public java.util.Iterator javaUtilIterator() {
    return new JavaUtilIterator(this);
  }

  /**
   * Returns a list iterator
   * 
   * @return
   */
  public static class LinkedListIterator implements Iterator, Externalizable {
    private LinkedList list;

    private LinkedListNode current;

    public void reset(final LinkedList list) {
      this.list = list;
      this.current = this.list.firstNode;
    }

    public Object next() {
      if (this.current == null) {
        return null;
      }
      final LinkedListNode node = this.current;
      this.current = this.current.getNext();
      return node;
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
      list = (LinkedList) in.readObject();
      current = (LinkedListNode) in.readObject();
    }

    public void writeExternal(ObjectOutput out) throws IOException {
      out.writeObject(list);
      out.writeObject(current);
    }

  }

  public static class JavaUtilIterator implements java.util.Iterator, Externalizable {
    private LinkedList list;

    private LinkedListNode currentNode;

    private LinkedListNode nextNode;

    private boolean immutable;

    public JavaUtilIterator() {

    }

    public JavaUtilIterator(final LinkedList list) {
      this(list, true);
    }

    public JavaUtilIterator(final LinkedList list, final boolean immutable) {
      this.list = list;
      this.nextNode = this.list.getFirst();
      this.immutable = immutable;
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
      list = (LinkedList) in.readObject();
      currentNode = (LinkedListNode) in.readObject();
      nextNode = (LinkedListNode) in.readObject();
      immutable = in.readBoolean();
    }

    public void writeExternal(ObjectOutput out) throws IOException {
      out.writeObject(list);
      out.writeObject(currentNode);
      out.writeObject(nextNode);
      out.writeBoolean(immutable);
    }

    public boolean hasNext() {
      return (this.nextNode != null);
    }

    public Object next() {
      this.currentNode = this.nextNode;
      if (this.currentNode != null) {
        this.nextNode = this.currentNode.getNext();
      } else {
        throw new NoSuchElementException("No more elements to return");
      }
      return this.currentNode;
    }

    public void remove() {
      if (this.immutable) {
        throw new UnsupportedOperationException(
            "This  Iterator is immutable, you cannot call remove()");
      }

      if (this.currentNode != null) {
        this.list.remove(this.currentNode);
        this.currentNode = null;
      } else {
        throw new IllegalStateException("No item to remove. Call next() before calling remove().");
      }
    }
  }

}

/**
 * Items placed in a <code>LinkedList<code> must implement this interface .
 *
 * @see LinkedList
 *
 * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
 * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
 */
interface LinkedListNode extends Externalizable {

  /**
   * Returns the next node
   * 
   * @return The next LinkedListNode
   */
  public LinkedListNode getNext();

  /**
   * Sets the next node
   * 
   * @param next
   *          The next LinkedListNode
   */
  public void setNext(LinkedListNode next);

  /**
   * Returns the previous node
   * 
   * @return The previous LinkedListNode
   */
  public LinkedListNode getPrevious();

  /**
   * Sets the previous node
   * 
   * @param previous
   *          The previous LinkedListNode
   */
  public void setPrevious(LinkedListNode previous);

}

interface Iterator extends Serializable {
  public Object next();
}








9.50.Your LinkedList
9.50.1.Demonstrating linked list
9.50.2.Finding and Deleting Specified Links
9.50.3.Double-Ended Lists: list with first and last references
9.50.4.Sorted Lists
9.50.5.A doubly-linked list
9.50.6.Iterators on a linked list
9.50.7.Linked List Entry
9.50.8.Demonstrating a stack implemented as a list
9.50.9.A simple linked List implementation
9.50.10.A simple Doubly Linked list class, designed to avoid O(n) behaviour on insert and delete.
9.50.11.A Queue Implemented by a Linked List
9.50.12.A class that wraps an array with a List interface.
9.50.13.List containing other lists
9.50.14.List implementation with lazy array construction and modification tracking.