I have implemented a simple iterator. Just want to check if I have missed anything.
interface iterator<E>
{
boolean hasNext();
E next();
}
class Iterator<E> implements iterator
{
E[] arr;
int curPos = 0;
@Override
public boolean hasNext()
{
if (curPos >= arr.length || arr[curPos] == null)
{
return false;
}
else
{
return true;
}
}
@Override
public E next()
{
if(hasNext())
{
E res = arr[curPos];
curPos++;
return arr[curPos+1];
}
else
{
throw new runtimeException("No next element available !");
}
}
}
Questions:
- Why should I not use
Object
instead ofE
/template everywhere ? - How do I make an iterator for a binary tree.
I assume apart from the above, I would have to implement a traversal algorithm and try to find if the next "traversal" successor exist?
-
\$\begingroup\$ It is not very clear what is asked in the second question. Could you clarify it or (what probably would be better) move it to a separate question? \$\endgroup\$CheatEx– CheatEx2011年06月05日 00:58:14 +00:00Commented Jun 5, 2011 at 0:58
4 Answers 4
I would write an iterator for arrays that way:
import java.util.Iterator;
import java.util.NoSuchElementException;
public class ArrayIterator<E> implements Iterator<E> {
private final E[] arr;
private int currentIndex = 0;
public ArrayIterator(E... arr) {
if(arr == null) {
throw new IllegalArgumentException("Array is null");
}
this.arr = arr;
}
public boolean hasNext() {
return currentIndex < arr.length;
}
public E next() {
if (! hasNext()) {
throw new NoSuchElementException();
}
return arr[currentIndex++];
}
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
}
To your second question: I assume you want to traverse the tree in-order, and that the nodes have no link to the parent, only to the children. Then you need a node list from the root node to the current node, which can store if a node was already visited or not, too.
Then you go left as deep as possible, storing the path in the node list. This is your first current node. When you need the next one, take its parent (from the node list). Next would be the right children of that node (if there are any) or its own parent. The best way to understand this is to take a sheet of paper, draw different trees, and look how the traversal must work.
-
\$\begingroup\$ Note, this will not be usable for arrays of primitives, e.g.
int[]
,boolean[]
, ... \$\endgroup\$Matt Ball– Matt Ball2011年06月08日 05:26:34 +00:00Commented Jun 8, 2011 at 5:26 -
\$\begingroup\$ @Matt: Yes, you would need specialized versions of that class, but this is a consequence from the insane way Java handles primitive arrays. You have that problem for all other collection stuff as well. On the other hand it's very easy to fix
E
to a wrapper likeInteger
and to adaptarray
and the constructor accordingly. \$\endgroup\$Landei– Landei2011年06月08日 08:23:08 +00:00Commented Jun 8, 2011 at 8:23
Because then the consumer of that code could write something like:
Iterator<Foo> iterator = new Iterator<Foo>();
//...
Foo theFoo = iterator.next();
instead of having to cast the object of type Object to type Foo like
Foo theFoo = (Foo)iterator.next();
It avoids potential confusion by being strict about what type of object to expect.
-
\$\begingroup\$ Thanks, I also see that being strict would also enforce that people dont start equating arrays to trees !! \$\endgroup\$p101– p1012011年06月04日 22:05:34 +00:00Commented Jun 4, 2011 at 22:05
The next method should throw an exception in case iterator reach the end. It is neither safe nor convenient to get an NPE after the iterator was used improperly.
If you don't define your own iterator, but use java.util.Iterator, you get this error from the compiler:
Iterator.java:9: Iterator is not abstract and does not override abstract method remove() in java.util.Iterator
To use it, where an Iterator is expected, you have to use the java.util.Iterator, which will not be too easy - removing from an array - but you could probably look up, how it is done in the Java source.
But then the compiler is your friend, and tells you, what is wrong.
For a tree, you could write implement multiple iterators - for depth-first traversal, or top-down.