Data Structures, Algorithms, & Applications in Java
Chapter 12, Exercise 48

We shall esentially perform a postorder traversal of the binary tree. The postorder traversal will need to be suspended whenever we find a node to visit because this node contains the element to be returned by next(). To find the next element in postorder, we will need to resume the traversal beginning at the current node. This resumption is best done by implementing the postorder traversal nonrecursively.

Exercise 12.32 does an iterative postorder traversal. You are urged to read the solution to Exercise 12.32 before proceeding. The constructor method for the enumerator must position us at the first node visited by a postorder traversal. This node is the leftmost leaf of the tree and is found by starting at the root and traversing a leaftmost path until a leaf is reached. Each node we make a move from is saved on a stack. As in Exercise 12.32, we need to distinguish between left child and right child moves made during this search for the left most leaf. So, we use the class StackElement defined in Exercise 12.32. Also, the code used to search for the leftmost leaf in the tree is written as a method which can actually find the leftmost leaf in any subtree.

Once we have identified the left most leaf, this node is saved in the data member nextNode. This data member gives us the next postorder node and it is null iff there is no next postorder node in the tree.

The code for the constructor and the methods iterator, leftMostLeaf, and hasNext is given below.
public class LinkedBinaryTreeWithPostorderIterator extends LinkedBinaryTree
{
   // define a class for use by the iterator
   static class StackElement
   {
      // data members
      BinaryTreeNode node;
      boolean leftChild;   // true iff we move to the left child of node

      // constructor
      public StackElement(BinaryTreeNode theNode, boolean theLeftChild)
      {
         node = theNode;
         leftChild = theLeftChild;
      }
   }

   /** create and return an iterator */
   public Iterator iterator()
      {return new PostorderIterator();}

   /** postorder iterator */
   private class PostorderIterator implements Iterator
   {
      // data members
      private BinaryTreeNode nextNode;  // next node in postorder
      private ArrayStack stack = new ArrayStack(10);
   
      // constructor
      /** set nextNode to first node in postorder */
      public PostorderIterator()
         {nextNode = (root == null) ? null : leftMostLeaf(root);}
   
      // methods
      /** @return the leftmost leaf in the subtree with root t
        * save nodes on the path to this leaf on the stack */
      BinaryTreeNode leftMostLeaf(BinaryTreeNode t)
      {
         BinaryTreeNode currentNode = t;
         while (true)
         {
            // move to leftmost node in subtree
            while (currentNode.leftChild != null)
            {
               stack.push(new StackElement(currentNode, true));
               currentNode = currentNode.leftChild;
            }

            // is this node a leaf?
            if (currentNode.rightChild == null)
               // it is a leaf, must be leftmost leaf
               return currentNode;

            // leftmost leaf is in right subtree of currentNode
            stack.push(new StackElement(currentNode, false));
            currentNode = currentNode.rightChild;
         }
      }

      /** @return true iff tree has more iterator */
      public boolean hasNext()
         {return nextNode != null;}

      /** return next element in postorder
        * throws NoSuchElementException
        * when there is no next element */
      public Object next()
      {
         if (nextNode != null)
         {
            Object obj = nextNode.element;
            
            // determine next postorder node
            if (stack.empty())
            {// there is no next node
               nextNode = null;
            }
            else
            {// there is a next node
               StackElement sElement = (StackElement) stack.pop();
               nextNode = sElement.node;
               if (sElement.leftChild && nextNode.rightChild != null)
               {// returning from left subtree of nextNode
                // incorrect nextNode, correct next node is leftmost
                // leaf in right subtree of nextNode
                  stack.push(new StackElement(nextNode, false));
                  nextNode = leftMostLeaf(nextNode.rightChild);
               }
            }
            return obj;
         }
         else throw new NoSuchElementException("No next element");
      }

      /** unsupported method */
      public void remove()
      {
         throw new UnsupportedOperationException
                   ("remove not supported");
      }   
   }
}



The method next() needs to simulate the portion of a postorder traversal from the visit of the last node to the visit of the next node. This is done by backing up from the last node visited to the node topNode at the top of the stack. If we are backing up from the right subtree of topNode or if topNode has an empty right subtree, topNode is the next postorder node. If we are backing up from the left subtree of topNode and if topNode has a nonempty right subtree, then the next postorder node is the leftmost leaf in this nonempty right subtree. The code is given below.
/** @return next element in postorder
  * @throws NoSuchElementException
  * when there is no next element */
public Object next()
{
   if (nextNode != null)
   {
      Object obj = nextNode.element;
      
      // determine next postorder node
      if (stack.empty())
      {// there is no next node
         nextNode = null;
      }
      else
      {// there is a next node
         StackElement sElement = (StackElement) stack.pop();
         nextNode = sElement.node;
         if (sElement.leftChild && nextNode.rightChild != null)
         {// returning from left subtree of nextNode
          // incorrect nextNode, correct next node is leftmost
          // leaf in right subtree of nextNode
            stack.push(new StackElement(nextNode, false));
            nextNode = leftMostLeaf(nextNode.rightChild);
         }
      }
      return obj;
   }
   else throw new NoSuchElementException("No next element");
}



Since our codes break up a postorder traversal into several steps, the time needed to get all elements in a tree using an enumerator is the same as that needed to perform a postorder traversal, that is O(n), where n is the number of nodes in the tree. So the average time per invocation is O(1). The stack height and the complexity of each method are readily seen to be O(h).