import rebelsky.util.List; import rebelsky.util.BinaryNode; import rebelsky.util.ListException; import rebelsky.util.EmptyListException; import rebelsky.util.Unimplemented; /** * A simple implementation of linked lists. Currently implements * singly linked lists (and therefore only a portion of the many * possible list functions). This implementation does ensure that * the cursor is always somewhere in the list. Hence, * the cursor-related functions are less likely to throw exceptions. *

* Copyright (c) 1998 Samuel A. Rebelsky. All rights reserved. * * @version 1.1 of March 1998 * @author Samuel A. Rebelsky */ public class LinkedList implements List { // +--------+-------------------------------------------------- // | Fields | // +--------+ /** * The number of elements in the list. */ protected int length; /** * The front of the list. */ protected BinaryNode front; /** * The back of the list. */ protected BinaryNode back; /** * The "current" element in the list. */ protected BinaryNode cursor; // +--------------+-------------------------------------------- // | Constructors | // +--------------+ /** * Create a new empty linked list. */ public void LinkedList() { clear(); } // LinkedList() // +-----------------------+----------------------------------- // | Information retrieval | // +-----------------------+ /** * Get the element referred to by the cursor. *
Precondition: * The list is nonempty. *
Postcondition: * The first element in the list is returned. *
Postcondition: * The list is not modified. *
Postcondition: * The cursor is not affected. * * @exception EmptyListException * if the list is empty. */ public Object getCurrent() throws EmptyListException { if (empty()) { throw new EmptyListException(); } return cursor.getContents(); } // getCurrent() /** * Get the first element in the list. *
Precondition: * The list is nonempty. *
Postcondition: * The first element in the list is returned. *
Postcondition: * The list is not modified. * * @exception EmptyListException * if the list is empty. */ public Object getFirst() throws EmptyListException { if (empty()) { throw new EmptyListException(); } return front.getContents(); } // getFirst() /** * Get the last element in the list. *
Precondition: * The list is nonempty. *
Postcondition: * The last element in the list is returned. *
Postcondition: * The list is not modified. * * @exception EmptyListException * if the list is empty. */ public Object getLast() throws EmptyListException { if (empty()) { throw new EmptyListException(); } return back.getContents(); } // getLast() /** * Determine whether the list is empty. *
Precondition: * (none) *
Postcondition: * The list is unaffected. */ public boolean empty() { // The list is empty if the front does not refer to an element. return (front == null); } // empty() /** * Determine the number of elements in the list. *
Precondition: * (none) *
Postcondition: * The list is uanffected. *
Postcondition: * The number of elements in the list is returned. */ public int length() { return length; } // length() // +--------------------+-------------------------------------- // | Inserting elements | // +--------------------+ /** * Add an element at the front of the list. If the list is * empty, creates a one-element list. *
Precondition: * (none) *
Postcondition: * The element is now at the front of the list. *
Postcondition: * The list increases in length by one. *
Postcondition: * If the list was not previously empty, the cursor is * unchanged (if it previously referred to the front of the list, * it now refers to the second element of the list). *
Postcondition: * If the list was previously empty, the list now has one element * which is front, back, and cursor. */ public void addAtFront(Object elt) { // Handle the empty list if (empty()) { newList(elt); } // Handle nonempty lists else { // Create the new front with the apprpropriate contents and // with the old front as the next element. BinaryNode new_front = new BinaryNode(elt, front); front = new_front; // Update the length length = length + 1; } } // addAtFront(Object) /** * Add an element at the end of the list. If the list is * empty, creates a one-element list. *
Precondition: * (none) *
Postcondition: * The element is now at the end of the list. *
Postcondition: * The list increases in length by one. *
Postcondition: * If the list was not previously empty, the cursor is * unchanged (if it previously referred to the end of the list, * it now refers to the penulitimate element of the list). *
Postcondition: * If the list was previously empty, the list now has one element * which is front, back, and cursor. */ public void addAtEnd(Object elt) { // Handle the empty list if (empty()) { newList(elt); } // Handle nonempty lists else { // Create the new front with the apprpropriate contents and // no subsequent element. BinaryNode new_back = new BinaryNode(elt); back.setNext(new_back); back = new_back; // Update the length length = length + 1; } } // addAtEnd(Object) /** * Add an element before the cursor. *
Precondition: * The list is nonempty. *
Postcondition: * The element is inserted before the cursor. *
Postcondition: * The list increases in length by one. *
Postcondition: * The cursor has not changed. * * @exception EmptyListException * if the list is empty. * @exception ListException * if some implementation-related error occurs. * @exception Unimplemented * until this implementation supports this method. */ public void addBeforeCurrent(Object elt) throws EmptyListException, ListException, Unimplemented { throw new Unimplemented(); } // addBeforeCurrent(Object) /** * Add an element after the cursor. *
Precondition: * The list is nonempty. *
Postcondition: * The element is inserted after the cursor . *
Postcondition: * The list increases in length by one. *
Postcondition: * The cursor has not moved. * * @exception EmptyListException * if the list is empty. */ public void addAfterCurrent(Object elt) throws EmptyListException { // Handle the empty list if (empty()) { throw new EmptyListException(); } // Handle nonempty lists else { // Create a new node whose contents is the given element and // whose subsequent element is the old successor to the cursor // element. BinaryNode new_elt = new BinaryNode(elt, cursor.getNext()); // Update the successor of the cursor cursor.setNext(new_elt); // Update the length length = length + 1; // Handle the special case of the cursor being the last element (in // which case the newly added element is now the last element). if (cursor == back) { back = new_elt; } // if (cursor == back) } // nonempty list } // addAfterCurrent(Object) // +-------------------+--------------------------------------- // | Deleting elements | // +-------------------+ /** * Delete all the elements in the list. *
Precondition: * (none) *
Postcondition: * The list is empty (contains no elements). */ public void clear() { length = 0; front = null; back = null; cursor = null; } // clear() /** * Delete the element referred to by the cursor. *
Precondition: * The list is nonempty. *
Postcondition: * The element referred to by the cursor is deleted. *
Postcondition: * The list decreases in length by one. *
Postcondition: * If the cursor was at the end of the list, it is now at the front * of the list. Otherwise, it has advanced to the next element of * the list. * * @return the deleted element. * @exception EmptyListException * if the list is empty. * @exception ListException * if some implementation-related error occurs. * @exception Unimplemented * until this implementation supports this method. */ public Object deleteCurrent() throws EmptyListException, ListException, Unimplemented { throw new Unimplemented(); } // deleteCurrent() /** * Delete the first element of the list. *
Precondition: * The list is nonempty. *
Postcondition: * The first element is deleted. *
Postcondition: * The list decreases in length by one. *
Postcondition: * If the cursor was at the front of the list, it is now at the * new front of the list. Otherwise, it is unchanged. * * @return the deleted element * @exception EmptyListException * if the list is empty. */ public Object deleteFirst() throws EmptyListException { // Handle the empty list if (empty()) { throw new EmptyListException(); } // Grab the old front BinaryNode tmp = front; // Deal with the cursor being at the front of the list if (cursor == front) { cursor = front.getNext(); } // Advance the front of the list front = front.getNext(); // And update the length length = length - 1; // Return the contents of the old front. return tmp.getContents(); } // deleteFirst() /** * Delete the last element of the list. *
Precondition: * The list is nonempty. *
Postcondition: * The last element is deleted. *
Postcondition: * The list decreases in length by one. *
Postcondition: * If the cursor was at the end of the list, it is now at the new * last element. Otherwise, it is unchanged. * * @return the deleted element. * @exception EmptyListException * if the list is empty. * @exception ListException * if some implementation-related error occurs. * @exception Unimplemented * until this implementation supports this method. */ public Object deleteLast() throws EmptyListException, ListException, Unimplemented { throw new Unimplemented(); } // deleteLast() // +------------------+---------------------------------------- // | Standard Methods | // +------------------+ /** * Develop a string version of the list. */ public String toString() { // Deal with the empty list. if (empty()) { return "()"; } // Nonempty lists: Start with open paren, follow with elements // separated by spaces String str = "("; BinaryNode tmp = front; // Keep going until we reach the end of the list while (tmp != back) { str = str + tmp.getContents().toString() + " "; tmp = tmp.getNext(); } // while // Add the last element str = str + tmp.getContents() + ")"; // That's it return str; } // toString() // +-------------------------+--------------------------------- // | Manipulating the cursor | // +-------------------------+ /** * Reset the cursor to the beginning of the list. *
Precondition: * The list is nonempty. *
Postcondition: * The cursor is at the beginning of the list. *
Postcondition: * The list is not modified. * * @exception EmptyListException * if the list is empty. */ public void reset() throws EmptyListException { if (empty()) { throw new EmptyListException(); } cursor = front; } // reset() /** * Advance the cursor. *
Precondition: * The list is nonempty. *
Precondition: * The cursor is not at the end of the list. *
Postcondition: * The cursor is advanced to the next element. *
Postcondition: * The list is not modified. * * @exception EmptyListException * if the list is empty. * @exception ListException * If the cursor is at the end of the list. */ public void advance() throws EmptyListException, ListException { if (empty()) { throw new EmptyListException(); } if (cursor.getNext() == null) { throw new ListException("Cannot advance beyond end of list"); } cursor = cursor.getNext(); } // advance() /** * Move the cursor backwards one position. *
Precondition: * The list is nonempty. *
Precondition: * The cursor is not at the beginning of the list. *
Postcondition: * The cursor is now at the previous element. *
Postcondition: * The list is not modified. * * @exception EmptyListException * if the list is empty. * @exception ListException * if some implementation-related error occurs or the cursor * is at the beginning of the list. * @exception Unimplemented * until this implementation supports this method. */ public void backup() throws EmptyListException, ListException, Unimplemented { throw new Unimplemented(); } // backup() /** * Advance the cursor to the first element equal to obj after (or * including) the cursor. If the cursor is not equal to obj and there * are no subsequent instances of obj, then return false and leave * the cursor where it was. *
Precondition: * The list is nonempty. *
Postcondition: * If there is an appropriate element in the list (equal to * obj and after or including the cursor) then the cursor * is at the first such object. * * @return true if an element is found; false otherwise. * @exception EmptyListException * if the list is empty. * @exception ListException * if some implementation-related error occurs. * @exception Unimplemented * until this implementation supports this method. */ public boolean find(Object obj) throws EmptyListException, ListException, Unimplemented { throw new Unimplemented(); } // find(Object) // +-----------------+----------------------------------------- // | Local Utilities | // +-----------------+ /** * Make a one-element list. Since I control who can call this, I don't * need to worry as much about exceptions. *
Precondition: * The list is empty. *
Postcondition: * The list contains exactly one element. */ protected void newList(Object elt) { // Create a new node BinaryNode new_node = new BinaryNode(elt); // Make everything refer to it front = new_node; back = new_node; cursor = new_node; // Set the length length = 1; } // newList(Object) } // List