CS-151 Labs > Lab 4. My LinkedList
Part 2. My ListIterator
Once MyLinkedList
class is working, you will need to create a
ListIterator
which is returned by the listIterator()
method. You can
do this through the use of a helper class MyLinkedListIterator
nested inside MyLinkedList
class, in the same way as it was implemented in the warmup:
class MyLinkedListIterator implements ListIterator<T> {
// Instance variables here
public MyLinkedListIterator() {
// constructor code here
}
public boolean hasNext() {
// Your code here
}
// other methods
}
The MyListIterator
returns an object that enables list traversals by moving one node at a time in
either direction. It might be helpful to think that the iterator has size+1
possible states: just before the head, between the 0 and 1 index, …,
just after the tail. After one call to next()
, the iterator is logically in
the state shown below:
You will need to implement all of the following methods. See interface ListIterator for details.
Public methods for MyListIterator
public boolean hasNext()
- Returns true if there are more elements when going in the forward direction.
public T next()
- Returns the next element in the list when going forward.
Throw a
NoSuchElementException
if there is no next element. public boolean hasPrevious()
- Returns
true
if there are more elements when going in the reverse direction. public T previous()
- Returns the next element in the list when going backwards.
Throw a
NoSuchElementException
if there is no previous element.
Programming Hints
Since the cursor of the ListIterator
can be logically placed between two nodes, it may be useful to keep references to both the current Node
and the next
Node
. You can also keep an int
value of the index of the next node.
If you construct your MyLinkedList
to use sentinel nodes as discussed in chapter 5.17,
you shouldn’t have to worry about checking for null
values at the ends of
the list since the special head and tail nodes are always there.
You will need to keep some state information for the Iterator
as well to
check if the underlying list has not been modified since the iterator was created.
Modifications can leave the iterator in an undefined state. This happens, for
example, when the nodes around the current index are deleted. Therefore you
should check that the list hasn’t been modified before you let an iterator
move to the next state.
An easy way to do this is to have both the list and the iterator keep track of
the number of modifications that have been made to the list. When the iterator
is created it grabs the list’s modification count. If the iterator finds that
its modification count is different from the list’s, you will know that the
list structure has been changed and that the iterator is no longer viable (it refers to a list which has been modified). See
modCount
for additional details and suggestions.
Throw a
ConcurrentModificationException
in these cases.
Public Methods to add to MyLinkedList
Once you are sure your iterator is working, you should override the following
methods in MyLinkedList
.
public ListIterator<T> listIterator()
public Iterator<T> iterator()
- These methods return a new instance of
MyListIterator
for the current list.
Testing your Iterator
You’ll want to test MyListIterator
and be sure that it works properly. You
should do this by printing out the entire list forwards and backwards using
your iterator. Start at the beginning of the list and call hasNext()
and
next()
using a loop until hasNext()
returns false
, printing out the entry at
each step. This is similar to how you computed the sum
in the warmup. Then,
use hasPrevious()
and previous()
to return each entry until the iterator
reaches the beginning of the list.
Test that if the underlying list is modified in the middle of the iteration (between two calls to next()
), your iterator throws a
ConcurrentModificationException
.