Mega Code Archive

 
Categories / Java Tutorial / Collections
 

A simple linked List implementation

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(); }