import Node; import CursoredList; import Comparator; import IncomparableException; /** * An implementation of cursored lists using linked lists, with nodes * that connect to each other. Written as part of the solution to * HW4 of CSC152 99F and also for exam 3 of the same course. * * Specific documentation for each method can be found in the CursoredList * interface. * * @author Samuel A. Rebelsky * @version 1.0 of November 1999 */ public class CursoredLinkedList implements CursoredList { // +--------+-------------------------------------------------- // | Fields | // +--------+ /** * The node that contains the first element of the list. This is set to * null (or, more precisely, Node.nil()) when the list is empty. */ protected Node front; /** * The node that contains the current element of the list. When this * is null, the position is unknown. */ protected Node cursor; // +--------------+-------------------------------------------- // | Constructors | // +--------------+ /** * Create a new empty list. */ public CursoredLinkedList() { front = Node.nil(); cursor = null; } // CursoredLinkedList() // +---------+------------------------------------------------- // | Methods | // +---------+ /** * Add an element to the end of the list. */ public void addToEnd(Object element) { // Special case: The list is empty. if (Node.isEmpty(front)) { // Create a new node for the front of the list. front = new Node(element, Node.nil()); } // Normal case: The list is nonempty else { // Find the last element in the list. Node finder = front; while (!(Node.isEmpty(finder.getNext()))) { finder = finder.getNext(); } // while // Add after that finder.setNext(new Node(element, Node.nil())); } // The list is nonempty } // addToEnd(Object) /** * Add an element to the front of the list. */ public void addToFront(Object element) { // Special case: The list is empty. if (Node.isEmpty(front)) { front = new Node(element, Node.nil()); } // Normal case: The list is nonempty. else { // (1) Create a new node for the front of the list. // (2) Set its next element to the old front. // (3) Update front to refer to the new node. front = new Node(element, front); } } // addToFront(Object) /** * Add an element after the current element. */ public void addAfterCursor(Object element) { // Don't have to worry about the special case in which the // list is empty, since the precondition says "the position // of the cursor is known", and the cursor has no known // position in the empty list. // (1) Create a new node whose next node is cursor's next element. // (2) Make that node the cursor's new next element. cursor.setNext(new Node(element, cursor.getNext())); } // addAfterCursor(Object) /** * Delete the current element. */ public void delete() { // Special case: The cursor is at the front of the list. if (cursor == front) { front = front.getNext(); // The position of the cursor is unspecified. cursor = null; } // cursor at front of the list // General case: The cursor is not at the front of the list. else { // Find the node that precedes the cursor. // Note that the loop must terminate if the cursor is in the list, // and the cursor being in the list is a precondition. Node finder = front; while (finder.getNext() != cursor) { finder = finder.getNext(); } // Skip over the cursor'd element. finder.setNext(cursor.getNext()); // Let Java clean up the deleted node. cursor = null; } // general case } // delete() /** * Move the cursor to the next element in the list equal * to the specified element. */ public void find(Object findMe) throws Exception { // If we need the NEXT equal element, we need to start after // the current element. cursor = cursor.getNext(); // Keep going until we run off the list or find a match while ( (cursor != null) && (!findMe.equals(cursor.getContents())) ) { cursor = cursor.getNext(); } // Have we run off the end of the list? if (cursor == null) { throw new Exception("Cannot find another copy of '" + findMe + "'"); } } // find(Object) /** * Move the cursor to the next element in the list equal * to the specified element, using compare for comparisons. */ public void find(Object findMe, Comparator compare) throws Exception { // Keep going until we run off the list or find a match. // This doesn't match the code above because the equals // method can throw an exception. boolean done = false; while (!done) { // If we need the NEXT equal element, we need to start after // the current element. cursor = cursor.getNext(); try { done = ( (cursor == null) || (compare.equals(findMe, cursor.getContents())) ); } catch (IncomparableException e) { // Do nothing. If the two things weren't comparable, so // they can't be equal. If we've already run off the end // of the list, cursor will be null, so we don't call the // exceptional code. } } // while // Have we run off the end of the list? if (cursor == null) { throw new Exception("Cannot find another copy of '" + findMe + "'"); } } // find(Object, Comparator) /** * Move the cursor to the front of the list. */ public void front() { cursor = front; } // front() /** * Get the current element of the list. */ public Object getCurrent() { return cursor.getContents(); } // getCurrent() /** * Advance the cursor to the next elmeent. */ public void advance() throws Exception { cursor = cursor.getNext(); if (cursor == null) { throw new Exception("Ran off of the list"); } } // advance() } // class CursoredLinkedList