10

I am pretty new to trees, and I am trying to create kind of a "leaf iterator". I'm thinking it should put all nodes that does not have a .left and .right value onto a stack, but I'm not sure how or even if it's the right thing to do. I have tried searching for it, but every example I come over starts with going to the leftmost leaf, and going p = node.parent, and I am avoiding linking to the node's parent.

I don't understand how I can repeatedlty start from the root and go through the vines without visiting the same vines over and over.

EDIT

I see people suggests using a recursive method to solve this, and I agree now. But I have been banging my head trying to find the solution for an iterator-class-way to do this for a while, and I still would like to know if that's possible, and how!

Sti
  • 8,275
  • 9
  • 62
  • 124

3 Answers3

20

Use recursion:

public void visitNode(Node node) {
    if(node.left != null) {
        visitNode(node.left);
    }
    if(node.right != null) {
        visitNode(node.right);
    }
    if(node.left == null && node.right == null) {
        //OMG! leaf!
    }
}

start it by supplying root:

visitNode(root);

In order to translate this into an Iterator<Node> you'll have to translate recursion to loop and then to traversal with state. Non-trivial, but should give you a lot of fun.

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • But would'n this only fine ONE leaf? The leftmost? – Sti Nov 05 '12 at 20:00
  • 1
    It uses the system stack to visit all leaves. – Whymarrh Nov 05 '12 at 20:02
  • 2
    @Sti: the keyword is **recursion**. Once it reaches the leftmost leaf it returns and gradually traverses the whole tree. – Tomasz Nurkiewicz Nov 05 '12 at 20:02
  • @TomaszNurkiewicz Okay, so turning the `if()if()if()` into `if()elseif()else()` would be a deal breaker in recursion-world? But for the fun of it, what do you mean by "translate recursion to loop and traversal with state"? This does sound fun. – Sti Nov 05 '12 at 20:20
  • 4
    @Sti: just try implementing an [`Iterator`](http://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html) over all leaves, you'll see the challenges. – Tomasz Nurkiewicz Nov 05 '12 at 20:23
4
class Node {
    public Node left = null;
    public Node right = null;
    // data and other goodies
}
class Tree {
    public Node root = null;
    // add and remove methods, etc.
    public void visitAllLeaves(Node root) {
        // visit all leaves starting at the root
        java.util.Stack<Node> stack = new java.util.Stack<Node>();
        if (root == null) return; // check to make sure we're given a good node
        stack.push(root);
        while (!stack.empty()) {
            root = stack.pop();
            if (root.left == null && root.right == null) {
                // this is a leaf
                // do stuff here
            }
            if (root.left != null) {
                stack.push(root.left);
            }
            if (root.right != null) {
                stack.push(root.right);
            }
        }
    }
}

I'm not sure if the above code works, but that's somewhere along the lines of what needs to be done. Another option is javax.swing.TreeModel (half-joking).

Whymarrh
  • 13,139
  • 14
  • 57
  • 108
1

Here is how one could implement an Iterator that would only return the leaf nodes, i.e. nodes without a left or right subtree.

The iterator searches for leaf nodes in the tree by doing a depth-first search, remembering the current state of the search in a stack and "pausing" when it has found a leaf node (see fetchNext() method).

The search is resumed when the client "consumes" the leaf node by calling next().

class Node {
  public Node left;
  public Node right;
}

class LeaveIterator implements Iterator<Node> {
  private final Stack<Node> stack = new Stack<>();
  private Node nextNode = null;

  public LeaveIterator(Node root) {
    if (root != null) {
      stack.push(root);
      nextNode = fetchNext();
    }
  }

  private void fetchNext() {
    Node next = null;
    while (!stack.isEmpty() && next == null) {
      Node node = stack.pop();
      if (node.left == null && node.right == null) {
        next = node;
      }
      if (node.right != null) {
        stack.push(node.right);
      }
      if (node.left != null) {
        stack.push(node.left);
      }
    }
    return next;
  }

  public boolean hasNext() {
    return nextNode != null;
  }

  public Node next() {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    Node n = nextNode;
    nextNode = fetchNext();
    return n;
  }

  public void remove() {
    throw new UnsupportedOperationException();
  }
}
applequist
  • 304
  • 3
  • 9
  • Could you explain _why_ this answers the question? The best answers include more than just code! – Ben Oct 23 '14 at 12:42