// Implementation of lists, using singly linked elements.
// (c) 1998, 2001 duane a. bailey
package structure5;
import java.util.Iterator;
import java.util.Enumeration;
/**
* An implementation of lists using singly linked elements, similar to that of {@link java.util.LinkedList java.util.LinkedList}.
*
* This class is a basic implementation of the {@link List} interface.
* Operations accessing or modifying the head of the list execute in constant
* time.
* Operations accessing or modifying the tail of the list execute in a time
* proportional to the length of the list.
* Singly linked lists are space-efficient, but tail-related operations may be more
* costly than with doubly linked lists.
*
* Example usage:
*
* To place a copy of every unique parameter passed to a program into a
* SinglyLinkedList, we would use the following:
*
* public static void main({@link java.lang.String String[]} arguments)
* {
* {@link SinglyLinkedList} argList = new {@link #SinglyLinkedList()};
* for (int i = 0; i < arguments.length; i++){
* if (!argList.{@link #contains(Object) contains(arguments[i])}){
* argList.{@link #add(Object) add(arguments[i])};
* }
* }
* System.out.println(argList);
* }
*
* @version $Id: SinglyLinkedList.java 31 2007-08-06 17:19:56Z bailey $
* @author, 2001 duane a. bailey
* @see DoublyLinkedList
* @see CircularList
*/
public class SinglyLinkedList extends AbstractList
{
/**
* The number of elements in list.
*/
protected int count; // list size
/**
* The head of the list. A reference to a singly linked list element.
*/
protected Node head; // ref. to first element
/**
* Construct an empty list.
*
* @post generates an empty list
*/
public SinglyLinkedList()
{
head = null;
count = 0;
}
/**
* Add an object to tail of list.
*
* @post value is added to end of list (see addLast)
*
* @param value The value to be added to tail of list.
*/
public void add(E value)
{
addLast(value);
}
/**
* Add a value to head of list.
*
* @post value is added to beginning of list
*
* @param value The value to be added to head of list.
*/
public void addFirst(E value)
{
// note order that things happen:
// head is parameter, then assigned
head = new Node(value, head);
count++;
}
/**
* Remove a value from first element of list.
*
* @pre list is not empty
* @post removes and returns value from beginning of list
*
* @return The value actually removed.
*/
public E removeFirst()
{
Node temp = head;
head = head.next(); // move head down list
count--;
return temp.value();
}
/**
* Add a value to tail of list.
*
* @post adds value to end of list
*
* @param value The value to be added to tail of list.
*/
public void addLast(E value)
{
// location for new value
Node temp = new Node(value,null);
if (head != null)
{
// pointer to possible tail
Node finger = head;
while (finger.next() != null)
{
finger = finger.next();
}
finger.setNext(temp);
} else head = temp;
count++;
}
/**
* Remove last value from list.
*
* @pre list is not empty
* @post removes last value from list
*
* @return The value actually removed.
*/
public E removeLast()
{
Node finger = head;
Node previous = null;
Assert.pre(head != null,"List is not empty.");
while (finger.next() != null) // find end of list
{
previous = finger;
finger = finger.next();
}
// finger is null, or points to end of list
if (previous == null)
{
// has exactly one element
head = null;
}
else
{
// pointer to last element is reset
previous.setNext(null);
}
count--;
return finger.value();
}
/**
* Fetch first element of list.
*
* @pre list is not empty
* @post returns first value in list
*
* @return A reference to first element of list.
*/
public E getFirst()
{
return head.value();
}
/**
* Fetch last element of list.
*
* @pre list is not empty
* @post returns last value in list
*
* @return A reference to last element of list.
*/
public E getLast()
{
Node finger = head;
Assert.condition(finger != null,"List is not empty.");
while (finger != null &&
finger.next() != null)
{
finger = finger.next();
}
return finger.value();
}
/**
* Check to see if a value is in list.
*
* @pre value is not null
* @post returns true iff value is found in list
*
* @param value The value sought.
* @return True if value is within list.
*/
public boolean contains(E value)
{
Node finger = head;
while (finger != null &&
!finger.value().equals(value))
{
finger = finger.next();
}
return finger != null;
}
/**
* Remove a value from list. At most one value will be removed.
*
* @pre value is not null
* @post removes first element with matching value, if any
*
* @param value The value to be removed.
* @return The actual value removed.
*/
public E remove(E value)
{
Node finger = head;
Node previous = null;
while (finger != null &&
!finger.value().equals(value))
{
previous = finger;
finger = finger.next();
}
// finger points to target value
if (finger != null) {
// we found element to remove
if (previous == null) // it is first
{
head = finger.next();
} else { // it's not first
previous.setNext(finger.next());
}
count--;
return finger.value();
}
// didn't find it, return null
return null;
}
/**
* Determine number of elements in list.
*
* @post returns number of elements in list
* @return The number of elements in list.
*/
public int size()
{
return count;
}
/**
* Remove all values from list.
*
* @post removes all elements from list
*/
public void clear()
{
head = null;
count = 0;
}
/**
* Get value at location i.
*
* @pre 0 <= i < size()
* @post returns object found at that location
*
* @param i position of value to be retrieved.
* @return value retrieved from location i (returns null if i invalid)
*/
public E get(int i)
{
if (i >= size()) return null;
Node finger = head;
// search for ith element or end of list
while (i > 0)
{
finger = finger.next();
i--;
}
return finger.value();
}
/**
* Set value stored at location i to object o, returning old value.
*
* @pre 0 <= i < size()
* @post sets ith entry of list to value o, returns old value
* @param i location of entry to be changed.
* @param o new value
* @return former value of ith entry of list.
*/
public E set(int i, E o)
{
if (i >= size()) return null;
Node finger = head;
// search for ith element or end of list
while (i > 0)
{
finger = finger.next();
i--;
}
// get old value, update new value
E result = finger.value();
finger.setValue(o);
return result;
}
/**
* Insert value at location.
*
* @pre 0 <= i <= size()
* @post adds ith entry of list to value o
* @param i index of this new value
* @param o value to be stored
*/
public void add(int i, E o)
{
Assert.pre((0 <= i) && (i <= size()),
"Index in range.");
if (i == size()) {
addLast(o);
} else if (i == 0) {
addFirst(o);
} else {
Node previous = null;
Node finger = head;
// search for ith position, or end of list
while (i > 0)
{
previous = finger;
finger = finger.next();
i--;
}
// create new value to insert in correct position
Node current =
new Node(o,finger);
count++;
// make previous value point to new value
previous.setNext(current);
}
}
/**
* Remove and return value at location i.
*
* @pre 0 <= i < size()
* @post removes and returns object found at that location
*
* @param i position of value to be retrieved.
* @return value retrieved from location i (returns null if i invalid)
*/
public E remove(int i)
{
Assert.pre((0 <= i) && (i < size()),
"Index in range.");
if (i == 0) return removeFirst();
else if (i == size()-1) return removeLast();
Node previous = null;
Node finger = head;
// search for value indexed, keep track of previous
while (i > 0)
{
previous = finger;
finger = finger.next();
i--;
}
// in list, somewhere in middle
previous.setNext(finger.next());
count--;
// finger's value is old value, return it
return finger.value();
}
/**
* Determine first location of a value in list.
*
* @pre value is not null
* @post returns the (0-origin) index of value,
* or -1 if value is not found
*
* @param value value sought
* @return index (0 is first element) of value, or -1
*/
public int indexOf(E value)
{
int i = 0;
Node finger = head;
// search for value or end of list, counting along way
while (finger != null && !finger.value().equals(value))
{
finger = finger.next();
i++;
}
// finger points to value, i is index
if (finger == null)
{ // value not found, return indicator
return -1;
} else {
// value found, return index
return i;
}
}
/**
* Determine last location of a value in list.
*
* @pre value is not null
* @post returns the (0-origin) index of value,
* or -1 if value is not found
*
* @param value value sought.
* @return index (0 is first element) of value, or -1
*/
public int lastIndexOf(E value)
{
int result = -1; // assume not found, return -1
int i = 0;
Node finger = head;
// search for last matching value, result is desired index
while (finger != null)
{
// a match? keep track of location
if (finger.value().equals(value)) result = i;
finger = finger.next();
i++;
}
// return last match
return result;
}
/**
* Returns an iterator traversing list from head to tail.
*
* @post returns enumeration allowing traversal of list
*
* @return An iterator to traverse list.
*/
public Iterator iterator()
{
return new SinglyLinkedListIterator(head);
}
/*
// THIS CODE IS NOT AVAILABLE
public int size()
// post: returns number of elements in list
{
// number of elements we've seen in list
int elementCount = 0;
// reference to potential first element
Node finger = head;
while (finger != null) {
// finger references a new element, count it
elementCount++;
// reference possible next element
finger = finger.next();
}
return elementCount;
}
*/
/**
* Construct a string representing list.
*
* @post returns a string representing list
*
* @return A string representing list.
*/
public String toString()
{
StringBuffer s = new StringBuffer();
s.append("");
return s.toString();
}
}