LinkedList.java Source code

Java tutorial

Introduction

Here is the source code for LinkedList.java

Source

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