Outline
- doubly-linked lists
- iterators
- iterator implementation
- the ListIterator interface
- the Java foreach statement
Doubly-Linked Lists
- the linked lists so far have the limitation that it is only
possible for code to follow references in one direction in the list,
that is, forward
- in such a singly-linked list (whether circular or not),
node removal requires a reference to the node before
the node to be removed
- if each node also keeps a reference to the node before it,
both these problems can be solved
- the node class is straightforward:
private class DLinkedNode<E> {
private E item;
private DLinkedNode<E> prev;
private DLinkedNode<E> next;
private DLinkedNode(E value) {
item = value;
next = null;
prev = null;
}
private DLinkedNode(E value, DLinkedNode<E> prev, DLinkedNode<E> next) {
item = value;
this.next = next;
this.prev = prev;
}
}
Doubly-Linked List add
Doubly-Linked List remove
- removing a given node (node) means updating the
node's predecessor's next field, and the
node's successor's prev field:
node.prev.next = node.next;
node.next.prev = node.prev;
- here are the special cases for a doubly linked-list that is not circular:
if ((node == head) && (head.next == null)) {
head = null;
} else {
if (node.prev != null)
node.prev.next = node.next;
if (node.next != null)
node.next.prev = node.prev;
}
- in-class exercise (alone or with a friend): write code to remove
the first (head) element of a doubly-linked circular list
Looping over the elements of a collection
Java Iterators
- a Java iterator only provides two or three operations:
- E next(), which returns the next element, and also
advances the references
- booleans hasNext(), which returns whether there is at
least one more element
- void remove(), which removes the last element returned
by next() (this method is optional)
- using remove may invalidate any other existing (concurrent)
iterators
Iterator Example
- The sieve of Eratosthenes is relatively simple using Linked Lists
and iterators:
private static java.util.LinkedList<Integer>
filter(java.util.LinkedList<Integer> list) {
java.util.LinkedList<Integer> result = new java.util.LinkedList<Integer>();
while (list.size() > 0) {
int first = list.getFirst(); // automatic unboxing of first
result.add(first); // add at the end of the result
list.removeFirst(); // now the linked list may be empty
java.util.Iterator<Integer> iter = list.iterator();
while (iter.hasNext()) {
if (iter.next() % first == 0) {
iter.remove(); // not prime, remove the number from the list
}
}
}
return result;
}
- in-class exercise (individually): write code to use an iterator
to add the values of all the elements of a
java.util.LinkedList<Number>
Iterator Implementation
- a Java iterator may or may not be internal to the collection class
- every Java iterator must have sequential access to the elements
of the collection
- every Java iterator must have at least one variable to keep track
of where it is in the traversal, that is, which elements have not yet
been returned
- the iterator could make a copy of the entire collection, but that
is unusual
- See
LinkedListIterator.java for a
very simple iterator on linked lists.
- in-class exercise (everyone together): design the code for
the iterator() method of the LinkedList class
ListIterator
- the Java Iterator interface is very general and reasonably powerful
- sometimes it is useful to be able to move backwards and forwards,
and add or replace as well as remove elements
- the ListIterator interface adds these operations to the
basic Iterator interface
- it also keeps track of the position and can return the index of
the next or previous item
Java for/foreach
- instead of having to use the while loop to use an iterator, the
for loop has been specialized to repeatedly call the iterator
LinkedList values = ...
int sum = 0;
for (Integer value: values) {
sum = sum + value;
}
- Java creates and calls the iterator, but the iterator itself is
not visible in the code
- this can also be used with arrays:
int [] values = ...
int sum = 0;
for (int value: values) {
sum = sum + value;
}
- this is called the Java enhanced for statement
or for each statement
- the foreach statement works on any expression that has a value
that satisfies the
Iterable interface, which simply requires an iterator method:
Iterator<E> iterator(); // create and return an iterator for this collection