Simple Linked List Class

/*
 *  Title: class LinkedList
 *  Description: Simple Linked List class to demonstrate the basic principles
 *  of implementing a linked list. This should not be taken as a production
 *  quality class (see the text book instead).
 *  Copyright:   Copyright (c) 2002
 *  Company:     Dept. of Computer Science, University College London
 *  @author Graham Roberts
 *  @version 1.0 01-Mar-02
 */

public class LinkedList
{
  /**
   * A list is a chain of ListElement objects. head references
   * the first object in the chain or is null if the list is
   * empty.
   */
  private ListElement head;

  /**
   *  Helper class used to implement list chain. As this is a private helper
   *  class it is acceptable to have public instance variables. Instances of
   *  this class are never made available to client code of the list.
   */
  private static class ListElement
  {
    /**
     *  Next node in chain reference.
     */
    public ListElement next;
    /**
     *  Data object reference.
     */
    public Object val;

    /**
     *  Constructor for ListElement.
     *
     *@param  next  next node in chain reference or null
     *@param  val   data object reference
     */
    public ListElement(ListElement next, Object val)
    {
      this.next = next;
      this.val = val;
    }

    /**
     *  Recursive helper method to copy a chain of ListElements.
     *
     *@return    reference to copied chain of elements.
     */
    public ListElement copy()
    {
      return new ListElement(next == null ? null : next.copy(), val);
    }
  }

  /**
   *  Constructor for LinkedList.
   */
  public LinkedList()
  {
    head = null;
  }

  /**
   *  Private helper constructor for LinkedList to quickly construct
   *  a new list given a chain of elements.
   *
   *@param  e  reference to element chain forming the list to be held by
   * the new list object. The chain is not copied.
   */
  private LinkedList(ListElement e)
  {
    head = e;
  }

  /**
   *  Insert a new value at the head of the list.
   *
   *@param  val  data object reference to insert.
   */
  public void insertHead(Object val)
  {
    head = new ListElement(head, val);
  }

  /**
   *  Return object at head of list. The list is unchanged.
   *
   *@return    reference to object at head of list or null if the
   * list is empty.
   */
  public Object getHead()
  {
    if (head == null)
    {
      return null;
    }
    else
    {
      return head.val;
    }
  }

  /**
   *  Return tail of list - the list that is the copy of the current
   * list minus the head element.
   *
   *@return    a new list that is a copy of the current list minus the head
   * element, or an empty list if there is no tail.
   */
  public LinkedList getTail()
  {
    if ((head == null) || (head.next == null))
    {
      return new LinkedList();
    }
    return new LinkedList(head.next.copy());
  }

  /**
   *  Test to see if list is empty.
   *
   *@return    true if list is empty, false otherwise.
   */
  public boolean isEmpty()
  {
    return head == null;
  }

  /**
   *  Iterator class for List to allow each list element to be
   *  visited in sequence. The iterator class is nested in the list class
   *  and is non-static meaning it has access to the state of the
   *  list object being iterated. The iterator is also public so iterator
   *  objects can be used by client code. As the class is nested, clients
   *  need to use the name LinkedList.Iterator to refer to the iterator
   *  class.
   */
  public class Iterator
  {
    /**
     * Instance variable used to store the current position of the iteration.
     * Note that it will be initialised to the head reference of the
     * LinkedList that creates the iterator (the nested iterator class is
     * in the scope of the LinkedList class, so the variable head is in scope).
     */
    private ListElement current = head;

    /**
     *  Determine if there is another element in the sequence, i.e.,
     *  another value in the list.
     *
     *@return    true if another element in the sequence is available, false
     * otherwise.
     */
    public boolean hasNext()
    {
      return current != null;
    }

    /**
     *  Return the object reference of the next value in the list. The position
     *  is moved forward before the value is returned.
     *
     *@return    the next object reference in the sequence or null if at the end
     * of the sequence.
     */
    public Object next()
    {
      Object temp = null;
      if (current != null)
      {
        temp = current.val;
        current = current.next;
      }
      return temp;
    }
  }

  /**
   *  Return a new Iterator object for the current list.
   *
   *@return    new iterator reference.
   */
  public Iterator iterator()
  {
    return new Iterator();
  }
}

JUnit test class for class LinkedList

/*
 * Title: class LinkedListTest
 * Description: JUnit test class for LinkedList class
 * Copyright:   Copyright (c) 2002
 * Company:     Dept. of Computer Science, University College London
 * @author Graham Roberts
 * @version 1.0 01-Mar-02
 */
import junit.framework.* ;

public class LinkedListTest extends TestCase
{
  private LinkedList empty ;
  private LinkedList one ;
  private LinkedList several ;

  public LinkedListTest(String s)
  {
    super(s) ;
  }

  public void setUp()
  {
    empty = new LinkedList() ;
    one = new LinkedList() ;
    one.insertHead(new Integer(0)) ;
    several = new LinkedList() ;
    several.insertHead(new Integer(2)) ;
    several.insertHead(new Integer(1)) ;
    several.insertHead(new Integer(0)) ;
  }

  public void testGetHead()
  {
    assertEquals("Check 0",new Integer(0),one.getHead()) ;
    assertEquals("Check 0",new Integer(0),several.getHead()) ;
    assertEquals("Check 1",new Integer(1),several.getTail().getHead()) ;
    assertEquals("Check 2",new Integer(2),several.getTail().getTail().getHead()) ;
  }

  public void testEmpty()
  {
    LinkedList temp = empty.getTail() ;
    assertNull("Check empty getHead null",empty.getHead()) ;
    assertTrue("Check empty getTail",temp.isEmpty()) ;
    assertTrue("Check one getTail",one.getTail().isEmpty()) ;
    assertTrue("Check several getTail x 3",several.getTail().getTail().getTail().isEmpty()) ;
  }

  public void testAddRemoveAdd()
  {
    one = one.getTail();
    assertTrue("one empty",one.isEmpty()) ;
    one.insertHead(new Integer(0));
    assertEquals("Check remove then add 0",new Integer(0),one.getHead()) ;
  }

  public void testIterator()
  {
    int counter = 0 ;
    for (LinkedList.Iterator iterator = empty.iterator() ; iterator.hasNext(); )
    {
      fail("Iterating empty list and found element") ;
    }
    counter = 0 ;
    for (LinkedList.Iterator iterator = several.iterator() ; iterator.hasNext(); )
    {
      assertEquals("Check several iteration",new Integer(counter++),(Integer)iterator.next()) ;
    }
  }

  public static Test suite()
  {
    return new TestSuite(LinkedListTest.class) ;
  }

  public static void main (String[] args)
  {
    junit.textui.TestRunner.run(suite()) ;
  }
}

No comments:

Post a Comment