We often need a way of cycling through all of the elements of a data structure. There exists a built-in interface in java.util:
public interface Enumeration { public boolean hasMoreElements(); // pre: Associated structure, S, is unchanged // post: true iff element of S has yet to be traversed. public Object nextElement(); // pre: S has more unenumerated elements // post: returns another element of S, marks it enumerated }
A data structure can create an object of type enumeration, which can be used to cycle through the elements. For example, built-in Java class Vector has a method:
public Enumeration elements()
Can print out the elements of Vector v as follows:
for (Enumeration enum=v.elements(); enum.hasMoreElement(); ) System.out.println(enum.nextElement());
Important Notes:
public interface Iterator extends Enumeration { // hasMoreElements(), nextElement() as before public void reset(); // post: the iterator is reset to beginning of traversal public Object value(); // pre: traversal has more elements // post: returns current value referenced by the iterator }Now can restart an iterator (rather than creating a new one) and also access a value without moving forward. value() returns the same object returned by the previous call of hasMoreElements().
The data structures in the structure library typically return an Iterator rather than an Enumeration.
We can now rewrite the for loop above in a slightly different manner:
for (Iterator iter = v.elements(); iter.hasMoreElement(); iter.nextElement()) System.out.println(iter.value());
This is now a bit clearer in showing how changes occur during each iteration of loop.
Have elements method in CircularList:
public Iterator elements() // post: returns iterator to traverse list elements. { return new CircularListIterator(tail); }
Let's see how code actually looks:
class CircularListIterator implements Iterator { protected SinglyLinkedListElement tail; protected SinglyLinkedListElement current; // element ready to look at next public CircularListIterator(SinglyLinkedListElement t) // pre: t is a reference to a circular list element // post: constructs iterator for traversing circular list { tail = t; reset(); } public void reset() // post: resets iterator to point to head of list { if (tail == null) current = null; else current = tail.next; } public boolean hasMoreElements() // post: returns true if some elements not visited { return current != null; } public Object nextElement() // pre: hasMoreElements() // post: returns current element, increments iterator { Object result = current.value; if (current == tail) current = null; else current = current.next; return result; } public Object value() // pre: hasMoreElements() // post: returns current value { return current.value; } }Notes:
for (Iterator iter = list.elements(); list.hasMoreElement(); list.nextElement()) System.out.println(list.value());
Recall again that Iterators are great for traversing a data structure, but should not be used to change the list as the results may not be predictable!