Introductory Laboratory on Linked Lists


Introduction to Doubly-Linked Lists

Summary: This laboratory provides some experience with doubly linked lists and with several capabilities of Java.

File ~walker/152/java-examples/DoubleOrderedList.java contains methods that comprise the beginning of a class that implements doubly-linked lists. Specifically, following the discussion from class, the DoubleOrderedList class contains the following methods:

This DoubleOrderedList class is very close to what was described in class, except that testing has been added in a main method.



  1. Copy this class to your account, compile it, and run it.

Exceptions

The behavior you observed in step 1 is achieved by the try and catch statements located through the code. The basic idea is this:

Throwing an Exception

The remove method of DoubleOrderedList provides a nice example. Within the remove method, a loop searches through the list to find the desired element. If the element is found, normal processing continues. However, if the element is not found, special action is needed. This is achieved with the statements:


if (current==null) 
    throw new NoSuchElementException
        (item.toString()+" is not in the list!");
if (current.data.compareTo(item)>0) 
    throw new NoSuchElementException
        (item.toString()+" is not in the list!");

The first of these tests indicates the item is not present, since the search continued through the entire list without finding the desired item. The second of these tests determines that searching went beyond where the desired item could possibly be found. In either case, the desired item is not present, and the code must signal normal processing cannot continue.

The signaling itself is accomplished with the statement


throw new NoSuchElementException
    (item.toString()+" is not in the list!");

Here, the throw new indicates that a signal is needed. The Java langauge includes many built-in such signals, and the NoSuchElementException illustrates one of these built-in capabilities. As this code illustrates, an exception may take a parameter (a string), which will be passed along to the exception handler.

Catching an Exception

The main method illustrates how such thrown exceptions are handled. Specifically, within the switch statement, several list methods are utilized, and we know some of them may raise exceptions. Thus, we place the entire switch statement within a try block. This try block tells the machine that some events might occur in what follows. If an exception is raised, processing should jump out the block to what immediately follows: one or more catch statements.

Each catch statement specifies a possible exception and indicates what processing should do to recover. In this case, a message is printed, although the code could seek to correct the error. This example also illustrates how to retrieve the message connected to the thrown exception. In each case, a variable exc was declared in the catch statement, and that variable is used with a getMessage method.

While Java contains a large number of built-in exceptions, a programmer rarely uses very many.

  1. Modify the add method so that insertion of more than 8 items on the list is forbidden. To do this,
    1. include a test early in add to be sure the current list contains no more than 7 items
    2. if the list contains at least 8 items, throw an IllegalArgumentException
    3. tailor the error message to indicate that the list has gotten too large


  2. Add a method findIth which takes a non-negative integer I as parameter and which returns the Ith item on the list. (Count the first item as item 0, the second as item 1, etc.) Raise an IndexOutOfBoundsException if the integer I is negative or if it is larger than the size of the list.
    Be sure to add code to catch this exception in the main method.

Note that main does incomplete testing for this program, because not all methods in the class are checked.

  1. Add menu options and code to main, so that methods destroy, isEmpty, and size are called and their results displayed appropriately.

Defining a Non-ordered Doubly-Linked List as a Subclass of DoubleOrderedList

In yesterday's class session, we discussed class hierarchies. This part of the lab presents an example of using one class to define another. In the jargon of object-oriented properties, the new class is called a subclass of the existing class, the old class is a superclass of the new class, and the new class inherits fields and methods from its superclass.

Class /home/walker/152/java-examples/MyFirstDoubleList.java is defined as a subclass of DoubleOrderedLlist using an extends clause at the start of the class defintion. That is, all data and methods of DoubleOrderedLlist extend to MyFirstDoubleList -- except where explicit changes or additions are made. In this case, method add is adjusted to allow the list to store duplicate elements, and a last method is added to print out the last item on the list. Also, since we want main to test DoubleOrderedLlist rather than DoubleOrderedLlist, the main method is adjusted slightly.

  1. Copy /home/walker/152/java-examples/MyFirstDoubleList.java to your account, compile it, and run it with some test data.

  2. Review the declarations of methods in DoubleOrderedLlist, and note that such class Node and fields head, tail, and size are declared as protected rather than private. A protected classification indicates that subclasses of DoubleOrderedLlist may use this private class and these fields, even though access is denied to applications. This is in contrast to a private designation which indicates that no other class (neither a subclass or an application) may access these entities.

    Change protected to private in DoubleOrderedLlist and try recompiling MyFirstDoubleList. What error messages do you get?

    When you are are done with this step, be sure to reinstate the protected designators before proceeding with the next steps of this lab.

  3. Add a method printBackward which takes a SimpleOutput object as parameter and which then prints the items on the list from the last node toward the front. (Thus, order of processing for printBackward will be exactly the reverse of toString -- although, of course, toString returns a string while printBackward actually prints.)

  4. Add a method countOccurences which takes an item as parameter and returns the number of times that item occurs on the list.


This document is available on the World Wide Web as

http://www.cs.grinnell.edu/~walker/courses/152.sp01/lab-doubly-linked-lists.html

created April 5, 2001
last revised April 6, 2001
Henry Walker (walker@cs.grinnell.edu)