com.github.rconner.anansi.PostOrderIterator.java Source code

Java tutorial

Introduction

Here is the source code for com.github.rconner.anansi.PostOrderIterator.java

Source

/*
 * Copyright (c) 2012-2013 Ray A. Conner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package com.github.rconner.anansi;

import com.github.rconner.util.PersistentList;
import com.google.common.base.Preconditions;
import com.google.common.collect.TreeTraverser;

import java.util.Iterator;

/**
 * Package implementation of the Iterator returned by {@link Traversals#postOrder(Object, TreeTraverser)}.
 *
 * @param <T> the vertex type
 *
 * @author rconner
 */
final class PostOrderIterator<T> implements Iterator<T> {
    private final TreeTraverser<T> adjacency;
    private PersistentList<Move<T>> stack;

    PostOrderIterator(final T root, final TreeTraverser<T> adjacency) {
        this.adjacency = adjacency;
        stack = PersistentList.of(new Move<T>(root, adjacency.children(root).iterator()));
    }

    @Override
    public boolean hasNext() {
        return !stack.isEmpty();
    }

    @Override
    public T next() {
        // stack.first() throws a NSEE if empty.
        while (stack.first().iterator.hasNext()) {
            final T vertex = stack.first().iterator.next();
            stack = stack.add(new Move<T>(vertex, adjacency.children(vertex).iterator()));
        }
        final T vertex = stack.first().vertex;
        stack = stack.rest();
        return vertex;
    }

    @Override
    public void remove() {
        Preconditions.checkState(!stack.isEmpty());
        stack.first().iterator.remove();
    }

    private static final class Move<T> {
        final T vertex;
        final Iterator<T> iterator;

        Move(final T vertex, final Iterator<T> iterator) {
            this.vertex = vertex;
            this.iterator = iterator;
        }
    }
}

/*
    
This is a step-by-step example of iterating with this Iterator. The example graph is below, child order is alphabetic.
    
      A
     / \
    B   C
   / \ / \
  E   D   F
    
The iteration order will be (walks from A to):
  D, E, B, D, F, C, A
    
The state of the Iterator is the state of its move stack, which will be written as:
    
          move.vertex  move.iterator
  bottom      A            [ B, * C ]
          B            [ D, E * ]
  top         E            [ ]
    
Or as just "empty" if there are no moves in the stack. The "*" in the iterator precedes the next vertex to be returned.
    
In the step-by-step below, colloquial language will be used (push, pop, top) rather than the actual method names.
    
"advance top and push next" means:
  vertex = top.iterator.next()
  push [ vertex, children(vertex).iterator() ]
So, advance the top iterator and push a move for its children.
    
    
@init
                                       A  [ * B, C ]
    
next()
  while( top.iterator not exhausted ) {    A  [ B, * C ]
advance top and push next              B  [ D, * E ]
  }                                        D  [ ]
    
  pop stack                                A  [ B, * C ]
                                       B  [ D, * E ]
    
  return popped move.vertex = D
    
next()
  while( top.iterator not exhausted ) {    A  [ B, * C ]
advance top and push next              B  [ D, E * ]
  }                                        E  [ ]
    
  pop stack                                A  [ B, * C ]
                                       B  [ D, E * ]
    
  return popped move.vertex = E
    
next()
  while( top.iterator not exhausted ) {    no change
advance top and push next     
  }
    
  pop stack                                A  [ B, * C ]
    
  return popped move.vertex = B
    
next()
  while( top.iterator not exhausted ) {    A  [ B, C * ]
advance top and push next              C  [ D, * F ]
  }                                        D  [ ]
    
  pop stack                                A  [ B, C * ]
                                       C  [ D, * F ]
    
  return popped move.vertex = D
    
next()
  while( top.iterator not exhausted ) {    A  [ B, C * ]
advance top and push next              C  [ D, F * ]
  }                                        F  [ ]
    
  pop stack                                A  [ B, C * ]
                                       C  [ D, F * ]
    
  return popped move.vertex = F
    
next()
  while( top.iterator not exhausted ) {    no change
advance top and push next     
  }
    
  pop stack                                A  [ B, C * ]
    
  return popped move.vertex = C
    
next()
  while( top.iterator not exhausted ) {    no change
advance top and push next     
  }
    
  pop stack                                empty
    
  return popped move.vertex = A
    
next()
  throw NoSuchElementException
    
*/