ICS 211 Homework 7

Sorted Linked List

0. Goals and Overview

The goal of this assignment is to learn about LinkedList implementations and to practice sorting.

A linked list is a data structure that stores a list of elements in a given sequence, and provides constant-time insertion and deletion of elements at the front of the linked list and sometimes at the back of the linked list. Unlike an array, a linked list grows as needed to accomodate more elements.

This assignment is consciously designed to mirror assignment 6, with the following differences:

  1. Implementing a linked list rather than an array list.
  2. The linked list is generic rather than specialized to store strings.

The remainder of this description is adapted as needed from the description in assignment 6.

This assignment requires you to implement a linked list that keeps its contents in sorted order. Your implementation will be somewhat similar to the implementation of a generic linked list, except that (a) your code will keep the strings in sorted order, and (b) your linked list will not keep any duplicate values. Your implementation will resemble that of a regular linked list in using a linked list of linked nodes to store all the contents of the sorted linked list.

The contents of the linked list must be kept in sorted order, that is, sorting occurs every time a value is added. The sorting algorithm you use is described in detail below, and is somewhat different than in Assignment 6.

For this assignment, you are not allowed to use any List class from the Java standard library or any outside source. Likewise, you are not allowed to call any sort method that you have not created yourself.

You are strongly encouraged to start with the code at LinkedList.java and any code in our textbook. Your LinkedList class must have instance variables head and size, but no tail variable. The absence of the tail variable is one difference from LinkedList.java.

1. Interface

Your SortedLinkedList class must implement the following SortedLinkedListInterface.
public interface SortedLinkedListInterface<T extends java.lang.Comparable<T>> {
  // List methods that are useful for a sorted linked list
  int size();
  // if the index is not valid, get throws java.lang.IndexOutOfBoundsException 
  T get(int index);
  // return true if the value has been added, false for null or already present
  boolean add(T value);
  // return true if the value has been removed, false if it was not present
  boolean remove(T value);
  // return the index at which the string can be found, or -1 if not found
  // even though the linked list is sorted, indexOf must use linear search
  int indexOf(T value);
  // return the contents with blanks (" ") in-between
  String toString();
}

Note there is no set method, since a call to set might break the invariant that the elements of the SortedLinkedList are in sorted order.

2. SortedLinkedList (60%)

Your SortedLinkedList class must implement SortedLinkedListInterface, and provide the six corresponding methods. Here is the class header for your SortedLinkedList class:

public class SortedLinkedList<T extends java.lang.Comparable<T>>
                             implements SortedLinkedListInterface<T> {

The contents must be stored in a sequence of LinkedNode objects. In a non-empty linked list, head must always refer to the first linked node.

The SortedLinkedList class must also have an integer variable size to keep track of the number of elements in the list, which is the size of the sorted linked list.

The constructor for SortedLinkedList takes no arguments and creates an empty SortedLinkedList with head initialized to null and size initialized to 0.

The add method must insert the value at the correct sorted position in the linked list. For example, if a linked list of strings already contains "a" as the item of the first linked node, "c" as the item of the second linked node, and "d" as the item of the third and last linked node (meaning that size would return 3), then adding "b" must add a new LinkedNode with item "b" right after the LinkedNode that refers to item "a". The resulting final sorted linked list will have size 4 and elements "a" at index 0, "b" at index 1, "c" at index 2, and "d" at index 3. This call to add would then return true.

For this sorted array list, the toString method must return the string "a b c d" -- there must be exactly one blank between two successive strings, and no blanks at the beginning or the end of the string. For an empty sorted array list toString must return "", the empty string. Since your code is generic, you must simply use your elements' toString method.

The sorting needed for the add method is to start at the beginning and insert the new value before any node containing a value for which value.compareTo(node.item) < 0. Be careful of special cases needed at the beginning and end of the linked list, and for empty linked lists. Also, if at any time during the search value.compareTo(node.item) == 0, add should return false.

Since null values cannot be compared, your add method should return false if its parameter is null.

Likewise, the remove method must start at the front of the list and remove from the list the LinkedNode containing the item to be removed. Again, removing at the front and end of the linked list may be special cases.

Since indexOf is doing a linear search, the search should end as soon as value.compareTo(node.item) < 0.

3. Testing (20%)

Add to your SortedLinkedList class a boolean unitTest() method that tests each of the above methods (the constructor, size, get, add, remove, indexOf, and toString) enough to convince yourself that they work. Each of the methods must be tested with an empty SortedLinkedList, a SortedLinkedList with one element, and a SortedLinkedList with more than one element. The value parameters to the calls must be null and multiple valid values. The index parameter to get must be negative, 0, 1, positive, and larger than the LinkedList.

Your unit test must create at least one non-empty list of Integer values and at least one non-empty list of String values.

Be sure this unit test catches and verifies the appropriate exception thrown when these methods throw exceptions.

Your unitTest must return true if all the tests pass and false otherwise. Your unitTest method should never throw any exceptions.

For this part you are welcome to reuse any code from your own Assignment 6.

4. Analysis (20%)

Give a clear analysis of the worst-case, best-case, and average-case execution time for each of the add and the remove methods. Each of the 6 analyses must include both a clear explanation, and a result of the form O().

If you have not completed the implementation in part 2, you can still get credit for this section by providing an analysis of your design for the add and remove methods -- be sure to describe your design in sufficient detail that the TA can tell what you are analyzing.

Turning in the Assignment

Once you are done, find your src directory and navigate to edu.ics211.h07, then turn the .java files and your analysis.txt into Laulima directly, without zipping or archiving.