/** * SLL.java * * Implementation of singly linked list. * WARNING: This implementation is guaranteed to work only if always given * immutable objects (or at least ones that do not change). * * @author THC * @author Scot Drysdale converted to Java * @author Scot Drysdale, THC have made a number of modifications. * @author Scot Drysdale most recently modified on 1/12/2011 * @author Prasad Jayanti changed the interface to CS10ListADT */ public class SLL implements CS10LinkedList { // Instance variables. private Element current; // current position in the list private Element head; // head of list private Element tail; // tail of list /** * A private class inner representing the elements in the list. */ private static class Element { // Because this is a private inner class, these can't be seen from outside SLL. private T data; // reference to data stored in this element private Element next; // reference to next item in list /** * Constructor for a linked list element, given an object. * @param obj the data stored in the element. */ public Element(T obj) { next = null; // no element after this one, yet data = obj; // OK to copy reference, since obj references an immutable object } /** * @return the String representation of a linked list element. */ public String toString() { return data.toString(); } } /** * Constructor to create an empty singly linked list. */ public SLL() { clear(); } /** * @see CS10ListADT#clear() */ public void clear() { // No elements are in the list, so everything is null. current = null; head = null; tail = null; } /** * @see CS10ListADT#add() */ public void add(T obj) { Element x = new Element(obj); // allocate a new element // There are two distinct cases, depending on whether the new element // is to be the new head. if (hasCurrent()) { // The new element is not the new head. x.next = current.next; // fix the next reference for the new element current.next = x; // fix the next reference for current element } else { // The new element becomes the new head. x.next = head; // new element's next pointer is old head head = x; // and the new element becomes the head } // And check whether we need to update the tail. if (tail == current) tail = x; current = x; // new element is current position } /** * * @see CS10ListADT#remove() */ public void remove() { Element pred; // current element's predecessor if (!hasCurrent()) { // check whether current element exists System.err.println("No current item"); return; } if (current == head) { head = current.next; // no predecessor, so update head pred = null; } else { // NOTE: Finding the predecessor makes remove a linear-time operation, // rather than a constant-time operation. for (pred = head; pred != null && pred.next != current; pred = pred.next) ; // At this point, either pred == null, in which case we never found the // current element on the list (an error), or pred.next == current. if (pred == null) { System.err.println("Current item is not part of list."); return; } pred.next = current.next; // splice current out of list } // If we're removing the tail of the list, update that information. if (tail == current) tail = pred; current = current.next; // make the successor the current position } /** * @return the String representation of this list. */ public String toString() { String result = ""; for (Element x = head; x != null; x = x.next) result += x.toString() + "\n"; return result; } /** * @see CS10ListADT#contains() */ public boolean contains(T obj) { Element x; for (x = head; x != null && !x.data.equals(obj); x = x.next) ; // We dropped out of the loop either because we ran off the end of the list // (in which case x == null) or because we found s (and so x != null). if (x != null) current = x; return x != null; } /** * @see CS10ListADT#isEmpty() */ public boolean isEmpty() { return head == null; } /** * @see CS10ListADT#hasCurrent() */ public boolean hasCurrent() { return current != null; } /** * @see CS10ListADT#hasNext() */ public boolean hasNext() { return hasCurrent() && current.next != null; } /** * @see CS10ListADT#getFirst() */ public T getFirst() { if(isEmpty()) { System.err.println("The list is empty"); return null; } current = head; return get(); } /** * @see CS10ListADT#getLast() */ public T getLast() { if (isEmpty()) { System.err.println("The list is empty"); return null; } else { current = tail; return get(); } } /** * @see CS10ListADT#addFirst() */ public void addFirst(T obj) { current = null; add(obj); } /** * @see CS10ListADT#addLast() */ public void addLast(T obj) { if(isEmpty()) addFirst(obj); else { getLast(); add(obj); } } /** * @see CS10ListADT#get() */ public T get() { if (hasCurrent()) { return current.data; } else { System.err.println("No current item"); return null; } } /** * @see CS10ListADT#set() */ public void set(T obj) { if (hasCurrent()) current.data = obj; else System.err.println("No current item"); } /** * @see CS10ListADT#next() */ public T next() { if (hasNext()) { current = current.next; return current.data; } else { System.err.println("No next item"); return null; } } }