Algorithms and OOD (CSC 207 2014F) : Labs

# Laboratory: Implementing Lists with Linked Nodes

Summary: We extend our understanding of a list ADT by considering an implementation of lists in which the values are stored in nodes that are linked together.

Prerequisite Knowledge: References. Interfaces. Generics. Anonymous inner classes. Iterators and list iterators.

## Preparation

Fork and clone the repository at https://github.com/Grinnell-CSC207/lab-linked-lists.

In a separate window or tab, open the documentation for `Iterator` and `ListIterator`.

Review your notes on iterators and list iterators.

## Exercises

### Exercise 1: A Simple Experiment

Read through the code of `SimpleListExpt.java` and `SLLExpt.java`.

a. Sketch the output you expect to see from `SLLExpt`.

b. Check your sketch experimentally.

### Exercise 2: Implementation Details

How are linked lists typically implemented? We have three issues to consider: How we represent the nodes, how we reference nodes in the `SimpleLinkedList` class, and how we represent iterators.

Nodes are elements of the `Node` class, which is a named inner class.

``` class Node
{
/**
* The data stored in the node.
*/
T data;

/**
* The next node in the list.  Set to null at the end of the list.
*/
Node next;

/**
* Create a new node with specified data and next.
*/
public Node(T data, Node next)
{
this.data = data;
this.next = next;
} // Node(T, Node)
} // class Node
```

What fields go in the list class? We have a field, `front`, that contains a reference to a `Node`. However, the node that `front` references is not actually the front of the list. Instead, it's a special “dummy” node that comes before the front of the list. Why do we make that choice? It turns out that it's helpful if we want to be able to insert elements - it lets us avoid special cases. We also have a second field field may be famililar from the array-based implementation of lists: a field, `mods` keeps track of the number of modifications to the list and is used to ensure that iterators “fail fast”.

```public class SimpleLinkedList<T>
implements SimpleList<T>
{
/**
* The dummy node at the front of the list.
*/
Node front;

/**
* The number of modifications to the list.  Used to determine
* whether an iterator is valid.
*/
long mods;
```

Because the iterators will need to access fields of the list, iterators are implemented as an anonymous inner class. Conceptually, iterators are between the values in the list. But it's not really possible to refer to something between two nodes. Hence, each iterator contains a field, `cursor`, that refers to the node that precedes the node that contains the value that will be returned by a subsequent call to `next`. (You will see that this approach makes the `add` method relatively easy to implement. However, it does not help us implement `remove`. We will revisit the difficulties in implementing `remove` in the future.

Do iterators need more than a reference to a `Node`? These iterators have two more fields. The field `pos` stores the index that value would have in an array-based implementation. (No, I don't think it's sensible to have such a field. But the list iterator interface expects us to be able to return integer indices.) And we have a `mods` field to help us decide whether or not the list has been changed by another iterator.

``` public ListIterator<T> listIterator()
{
return new ListIterator<T>()
{
/**
* The node that immediately precedes the value to be returned
* by next.
*/
Node cursor = SimpleLinkedList.this.front;

/**
* The position in the list. (Included because the folks
* at Sun/Oracle decided that list iterators need to be
* able to return integer indices.)
*/
int pos;

/**
* The number of modifications at the time this iterator was
* created or last updated.
*/
long mods = SimpleLinkedList.this.mods;
```

a. Sketch how you would implement the `next` method in the itetrator.

b. Compare your answer to the implementation given in `SimpleLinkedList.java`.

c. Sketch how you would implement the `hasNext()` method.

d. Compare your answer to the implementation given in `SimpleLinkedList.java`.

e. Sketch how you would implement the `add(T val)` method.

f. Compare your answer to the implementation given in `SimpleLinkedList.java`.

### Exercise 3: Implement `set`

Here's a simple experiment to test the set method while iterating forward through a list.

```    SimpleLinkedList<String> vm = new SimpleLinkedList<String>();
SimpleListExpt.add(pen, vm,
new String[] { "Hey", "Where", "Did", "We", "Go?" });
SimpleListExpt.setForwardExpt(pen, vm);
```

a. Suppose the `set` method is correctly implemented. What should the output of the experiment be?

b. Look at the current implementation of `set`. What do you expect the output to be?

c. Check your answer experimentally.

d. You've probably noted that `set` is not yet implemented. Assume that we're only going to iterate the list from front to back. Sketch how you might implement `set`.

e. Here's a simple strategy for implementing `set`, assuming that we only iterate lists forward. Since `cursor` refers to the node that immediately precedes the next value, it must refer to the node last returned by `next`. Hence, we can implement `set` by setting the `data` field of `cursor`.

Implement `set`, using your approach or this approach (or both, if they are the same).

f. Rerun the experiment to see if the approach you selected works.

### Exercise 4: Moving Backwards

You'll note that the `previous` method and the `hasPrevious` method are not implemented.

a. Add the following line to your experiments.

```    SimpleListExpt.prevExpt(pen, new SimpleLinkedList<String>());
```

b. Read through `SimpleListExpt.java` to see how `prevExpt` exercises the `previous` and `hasPrevious`.

c. Sketch a strategy for implementing `previous` and `hasPrevious`.

d. Here's one strategy: To find the previous element, start at the front of the list and move forward until you're immediately before the cursor. You have a previous element if you're not the front of the list.

What do you think about this strategy?

e. Implement `previous` and `hasPrevious` using one those strategies.

f. Check whether the methods work by using the experiment from the beginning of this problem.

### Exercise 5: Setting Elements, Revisited

When we first implemented `set`, we assumed that it only had to work if we iterated the list from front to back. Now we can iterate the list in both directions.

a. Look at `SimpleListExpt.setBackwardsExpt` to see one way to exercise `set` while iterating the list from back to front.

b. What do you expect the results of the following experiment to be?

```    SimpleListExpt.addToEnd(pen, vm,
new String[] { "Days", "When", "The", "Rain", "Came" });
SimpleListExpt.setBackwardExpt(pen, vm);
```

c. Check your answer experimentally.

d. If the experiment suggests that `set` is no longer implemented correctly, find a way to make it work correctly. Hint: One strategy is to add a field to the iterator that refers to the last node visited.

## For Those With Extra Time

Consider how you might write the `remove` method.

Consider how our lists might change if we included a previous link in addition to a next link.