/*
* DoublyLinkedList.java
*
* Created on December 11, 2000, 2:24 PM
*/
package org.limewire.collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
/**
* Provides a doubly-linked list. Unlike the {@link LinkedList} class in the
* JDK, <code>DoublyLinkedList</code> provides a way to refer to elements of
* the list (each of type <code>ListElement</code>)
* directly, avoiding linear-time searches when you wish to remove an element.
* <p>
* This class is not thread-safe.
* <pre>
DoublyLinkedList<String> dll = new DoublyLinkedList<String>();
dll.addLast("Abby");
dll.addLast("Bob");
dll.addLast("Chris");
ListElement<String> dan = dll.addLast("Dan");
for(DoublyLinkedList.ListElement<String> e : dll)
System.out.println(e.getKey());
dll.remove(dan);
System.out.println("");
for(DoublyLinkedList.ListElement<String> e : dll)
System.out.println(e.getKey());
Output:
Abby
Bob
Chris
Dan
Abby
Bob
Chris
</pre>
* @author Anurag Singla initial revision
* @author Christopher Rohrs bug fix, specification cleanup, and unit tests
*/
public class DoublyLinkedList<E> implements Iterable<DoublyLinkedList.ListElement<E>> {
/*
* This linked list can be visualized as
* null<--start<-->e1<-->e2<-->...<-->en<-->last-->null,
* where e1, e2,...en are the stored elements in the list
*/
/**
* points to the first element in the list (thru its next element)
* INVARIANT: prev, & value fields are always null for this
*/
private ListElement<E> start;
/**
* points to the last element in the list (thru its prev element)
* INVARIANT: next, & value fields are always null for this
*/
private ListElement<E> last;
/** Creates new empty DoublyLinkedList. */
public DoublyLinkedList()
{
//allocate space for both start & last pointers
//The prev & next fields will be pointing to null at this point
//in both the references
start = new ListElement<E>(null);
last = new ListElement<E>(null);
//since no elements right now, make start & last point to each other
start.next = last;
last.prev = start;
}
/**
* Inserts an object at the end of the list, returning its
* corresponding element.
* @param value the value of the new element
* @return the element holding value
*/
public ListElement<E> addLast(E value)
{
ListElement<E> element=new ListElement<E>(value);
//else insert at the end
element.prev = last.prev;
element.next = last;
element.prev.next = element;
last.prev = element;
return element;
}
/**
* Removes and returns the first element from the list
* @return The element removed, or null if none present
*/
public ListElement<E> removeFirst()
{
//if no element in the list, return null
if(start.next == last)
return null;
//else store the element to be removed/returned
ListElement<E> removed = start.next;
//adjust the pointers
start.next = start.next.next;
start.next.prev = start;
//return the removed element
return removed;
}
/**
* Removes the specified element from the list.
* @param element the element to be removed. This must be an element
* of this.
*/
public void remove(ListElement<E> element)
{
//if null element or invalid state, return false
//No element in the list is gonna have any of the pointers null
if(element == null || element.prev == null || element.next == null)
return;
//also start and last cant be removed
if(element == start || element == last)
return;
//adjust the pointers to remove the element from the list
element.prev.next = element.next;
element.next.prev = element.prev;
}
/**
* Removes all entries from this list.
*/
public void clear() {
//since no elements, make start & last point to each other
start.next = last;
last.prev = start;
}
/*
* Returns an iterator that yields the ListElement's in this,
* each once, in order, from head to tail. Call getValue() on
* each element to get the values in this.
* @requires this not modified while iterator in use.
*/
public Iterator<ListElement<E>> iterator() {
return new DoublyLinkedListIterator();
}
/**
* Returns true if this contains the given ListElement.
*/
public boolean contains(ListElement<E> e) {
for(ListElement<E> e2 : this) {
if (e.equals(e2))
return true;
}
return false;
}
private class DoublyLinkedListIterator extends UnmodifiableIterator<ListElement<E>> {
/** The next element to yield, or last if done. */
private ListElement<E> next = start.next;
public boolean hasNext() {
return next!=last;
}
public ListElement<E> next() {
if (! hasNext())
throw new NoSuchElementException();
ListElement<E> ret=next;
next=next.next;
return ret;
}
}
/**
* Represents an immutable element of the linked list.
<pre>
DoublyLinkedList<String> dll = new DoublyLinkedList<String>();
dll.addLast("Abby");
dll.addLast("Bob");
dll.addLast("Chris");
ListElement<String> dan = dll.addLast("Dan");
for(DoublyLinkedList.ListElement<String> e : dll)
System.out.println(e.getKey());
dll.remove(dan);
System.out.println("");
for(DoublyLinkedList.ListElement<String> e : dll)
System.out.println(e.getKey());
Output:
Abby
Bob
Chris
Dan
Abby
Bob
Chris
</pre>
*/
public static class ListElement<E> {
/**
* The key/object it stores.
*/
E key;
/**
* Reference to the previous element in the list.
*/
ListElement<E> prev;
/**
* Reference to the next element in the list.
*/
ListElement<E> next;
/**
* Creates a new instance, with the specified key.
* @param key the key/value to be stored in this list element
*/
ListElement(E key) {
//store the object
this.key = key;
//make both the forward & backward pointers null
prev = null;
next = null;
}
/**
* @return the key stored in this element
*/
public E getKey() {
return key;
}
}
}