Computer Science 210
Data Structures

Fall 2018, Siena College

Lab 7: Linked List Practice
Due: 4:00 PM, Tuesday, November 6, 2018

You will be assigned a partner to work with on this lab. Only one submission per group is needed.

As you finish each step, please have your instructor initial the hard copy of this lab handout you were issued to indicate successful completion.

Names:

Learning goals:

  1. To gain expertise drawing a memory diagram for a recursive data structure.
  2. To learn how to implement recursive methods for an opaque recursive data structure.
  3. To learn about the implementation details of iterators by implementing one for an existing class.

Submitting

As you complete each programming task, commit with a meaningful commit message and push to your group's GitHub repository for this lab.

Once all written items are initialed to indicate completion, turn in the hard copy of this lab handout you were issued.

Getting Set Up

You will receive an email with the link to follow to set up your GitHub repository for this Lab (listpractice-lab-yourgitname). One member of the group should follow the link to set up the repository on GitHub. Other group members will receive a subsequent email with a link to follow that will grant them the rights to clone the repository and commit and push changes to the origin on GitHub.

A Linked List Memory Diagram

Consider the following program:

public class SimpleLinkedListExample {

    public static void main(String args[]) {

        SimpleLinkedList<GenericPair<Integer,String>> a = 
            new SimpleLinkedList<GenericPair<Integer,String>>();

        a.add(new GenericPair<Integer,String>(120,"Intro to Programming"));
        // draw first diagram of memory when the get method call below
        // is about to return its value
        System.out.println("Added " + a.get(0));        
        a.add(new GenericPair<Integer,String>(210,"Data Structures"));
        a.add(new GenericPair<Integer,String>(225,"Advanced Programming"));
        
        // find and remember the GenericPair with the longest String
        Iterator<GenericPair<Integer,String>> i = a.iterator();
        GenericPair<Integer,String> longest = i.next();
        while (i.hasNext()) {
            GenericPair<Integer,String> pair = i.next();
            if (pair.getSecond().length() > longest.getSecond().length()) {
                longest = pair;
                // draw second diagram of memory at this point when pair
                // refers to the (210, "Data Structures") GenericPair object
            }
        }
        System.out.println(longest);
    }
}

As you can see, it uses two classes from previous examples: GenericPair and SimpleLinkedList.

Question 1: Draw a complete memory diagram showing the state of objects and variables in memory at the execution point indicated by the comment near the top of the main method shown above. Include the implicit this reference for any non-static method in execution. (10 points)

Question 2: Draw a complete memory diagram showing the state of objects and variables in memory at the execution point indicated by the comment near the bottom of the main method shown above. Include the implicit this reference for any non-static method in execution. Note that this will be at the end of the second iteration of the while loop. (15 points)

Recursive SimpleLinkedList Methods

The methods of the RatioList linked list were all recursive. We can also write recursive versions of the SimpleLinkedList methods. For example, we could rewrite add as follows:

   public void add(int pos, E obj) {

        if (pos < 0) {
            throw new IndexOutOfBoundsException(
              "Attempt to add at negative position " + pos);
        }
        head = add(pos, obj, head);
    }

    private SimpleListNode<E> add(int pos, E obj, SimpleListNode<E> startAt) {

        if ((startAt == null) && (pos != 0)) {
            throw new IndexOutOfBoundsException("Position too large for add");
        }

        // are we adding at the front of this part?
        if (pos == 0) {
            return new SimpleListNode<E>(obj, startAt);
        }

        // we are adding somewhere else, so let the recursion do the work
        SimpleListNode<E> newNext = add(pos - 1, obj, startAt.next());
        startAt.setNext(newNext);
        return startAt;
    }

Notice that we needed to add a private helper method that is aware of the internals of the list structure (it takes an extra parameter which is a SimpleListNode that we can use to "walk" down the structure recursively).

Question 3: Describe, in English (no code/pseudocode!), what is the base case for the recursion in the add method above and what it does in that case. (2 points)

Question 4: Describe, in English (no code/pseudocode!), the recursive case for the add method above and how it makes progress toward the base case. (3 points)

Question 5: In the recursive case, when the recursive call returns, what additional work does it do to ensure that the list structure remains correct? (3 points)

Your next tasks will replace a few other SimpleLinkedList methods with recursive equivalents. Please answer the lab questions first and get your answers approved before moving on to implementation. [Good news: as accessors rather than mutators, these are substantially simpler than the add method above.]

We will first work toward a recursive contains method.

Question 6: As with the add example implementation, your contains method will first need a private helper method with extra information to manage the recursion. What additional parameter(s) will the helper method need, and what will it/they be passed initially? (4 points)

Question 7: As the recursive contains "walks" down the list recursively, under what circumstances can it immediately return false, immediately return true, or when does it need to make a recursive call to obtain its answer? (4 points)

Question 8: When it needs to make a recursive call, how will the recursive contains method use the answer obtained by the recursive call to get its own answer? (2 points)

Once your responses above have been approved, implement the recursive contains method in SimpleLinkedList and test cases. Test cases should include a call on an empty list, calls that find the value located in the first position, somewhere in the middle, and at the last position, and calls that do not find the value on lists of at least two different sizes.

Question 9: Demonstrate your working recursive contains method and tests. (6 points)

Next, we work toward a recursive get method implementation.

Question 10: What parameter(s) will the recursive helper method for get need, and what will it/they be passed initially? (3 points)

Question 11: What is the base case/stopping condition for the recursive get? (2 points)

Question 12: Describe, in English (no code/pseudocode!), the recursive case. Your response is started for your below. (3 points)

In the recursive case, get method will make a recursive call where the parameters

Question 13: When it needs to make a recursive call, how will the recursive get method use the answer obtained by the recursive call to get its own answer? (2 points)

Once your responses above have been approved, implement the recursive get method in SimpleLinkedList and test cases. Test cases should include a call on an empty list (which will throw an exception, so you can comment it out after you've verified it works), calls that find the value located in the first position of a one-element and a multi-element list, calls that find the value somewhere in the middle, a call that finds the value at the last position, and a call that tries to get a value on a list that does not contain enough elements for that to succeed (another that will throw and exception).

Question 14: Demonstrate your working recursive get method and tests. (6 points)

Question 15: Describe, in English (no code/pseudocode!), how a recursive version of toString would work. You need not implement it. (5 points)

Question 16: Describe, in English (no code/pseudocode!), how a recursive version of toString would work, but this time one that prints the values in reverse order. You need not implement it. (5 points)

Question 17: Describe, in English (no code/pseudocode!), how a recursive version of remove would work. You need not implement it. (5 points)

Iterator Practice

We looked at the idea of iterators in the context of our SimpleLinkedList, but they are typically provided by any data structure that stores a collection of elements. Let's consider this idea in the context of our old friend, the DoubleArrayList.

Question 18: Which methods are required to be provided by a class that implements the java.util.Iterator interface? (1 point)

In order to operate correctly and efficiently, an iterator should maintain some state (in one or more instance variables) that allow it to determine if the iteration is complete and to return the next unvisited element. Think of it like a "bookmark" that remembers where to pick up on the next iteration.

Question 19: What is the instance variable of the SimpleListIterator, and how does it determine whether the iterator has more elements to return and how does it help the iterator return the next unvisited element? (2 points)

Question 20: Now turning attention to the iterator for the DoubleArrayList, what state will it need to maintain in its instance variable(s) to support correct and efficient iteration over that structure? (4 points)

Here are the steps to implement an iterator for DoubleArrayList:

Question 21: Demonstrate your implementation and tests for the DoubleArrayList's iterator functionality. (12 points)

Don't forget to commit and push all of your code for this lab to your group's GitHub repository.