0

Been working on this for while with no luck. Hopefully someone can point in the right direction.

Code:

public class BST {
  public BTNode<Integer> root;
  int nonLeafCount = 0;
  int depthCount = 0;

  public BST() {
    root = null;
  }



  class BTNode<T> {
    T data;
    BTNode<T> left, right;

    BTNode(T o) {
      data = o;
      left = right = null;
    }

    public String toString() {
      return String.valueOf(data);
    }
  }
}
bob9123
  • 725
  • 1
  • 9
  • 31
  • http://stackoverflow.com/a/5496559/277106 or http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/ – Genti Saliu Feb 09 '16 at 18:05
  • 1) create a `Deque`. 2) add `root` to the `Deque`. 3) `while` the `Deque` is not empty, pop `head`. 4) add (and count) all non-leaf nodes from popped element. Done. This is a BFS. – Boris the Spider Feb 09 '16 at 18:11
  • @GentiSaliu I cannot use the stack library. – bob9123 Feb 09 '16 at 18:14
  • @BoristheSpider I cannot use external libraries such as pop/empty etc. Needs to be implemented from scratch. – bob9123 Feb 09 '16 at 18:16
  • Maybe mentioning that in the question might be have been jolly helpful. Implement a simple stack with an array. Not difficult. – Boris the Spider Feb 09 '16 at 18:17
  • Sorry I don't understand. I have made a binary search tree that needs to be traversed so I can get the amount of non leaf nodes. How will implementing a stack w/ array help me? – bob9123 Feb 09 '16 at 18:23

2 Answers2

1

The easy way to traverse a tree without recursive calls is to use a stack. Push the root on the stack, then enter a loop that - so long as the stack is not empty - pops a node from the stack and pushes the non-null children of that node. It's pretty obvious that this will eventually push every node onto the stack exactly once and pop it exactly once. Now all you need to do is count the popped nodes that have at least one child. Putting this together,

public int nonleaves() {
  int nonLeafCount = 0;
  BTNode<Integer> [] stack = new BTNode[2];
  int p = 0;
  stack[p++] = root; // push root
  while (p != 0) {
    BTNode<Integer> node = stack[--p]; // pop
    if (node.left != null || node.right != null) ++nonLeafCount;
    if (p + 1 >= stack.length) stack = Arrays.copyOf(stack, 2 * stack.length);
    if (node.right != null) stack[p++] = node.right; // push right
    if (node.left != null) stack[p++] = node.left;   // push left
  }
  return nonLeafCount;
}

Note that in accordance with your description, I used a simple Java array for a stack, growing it by a factor of 2 whenever it fills up. Integer p is the stack pointer.

Also, this code assumes the root is non-null. If the root can be null, add a check at the start and return 0 in that case.

NB it's possible to traverse without even a stack by several methods, although at the cost of changing the tree during traversal. (It's back in its original shape when the traversal is complete.) The nicest IMO is Morris's algorithm, but all of them are considerably more complicated than the stack. Since it seems you're a new programmer, figure out the stack method first.

Edit

To find max depth:

public int maxDepth() {
  int max = 0;
  Pair<Integer> [] stack = new Pair[2];
  int p = 0;
  stack[p++] = new Pair(root, 1);
  while (p != 0) {
    Pair<Integer> pair = stack[--p];
    if (pair.depth > max) max = pair.depth;
    if (p + 1 >= stack.length) stack = Arrays.copyOf(stack, 2 * stack.length);
    if (pair.node.right != null) 
      stack[p++] = new Pair(pair.node.right, 1 + pair.depth);
    if (pair.node.left != null) 
      stack[p++] = new Pair(pair.node.left, 1 + pair.depth);
  }
  return max;
}

private static class Pair<T> {
  BTNode<T> node;
  int depth;
  Pair(BTNode<T> node, int depth) {
    this.node = node;
    this.depth = depth;
  }
}

Finally, I'd be remiss if I didn't point out that we can do some algebra on the algorithm to eliminate some tiny inefficiencies. You'll note that after the left child is pushed onto the stack, it is certain to be popped in the next loop iteration. The root push/pop is similar. We might as well set node directly. Also, there are some redundant comparisons. The details are too much for this note, but here is a reworked non-leaf counter (untested but ought to work fine):

public int nonleaves() {
  int nonLeafCount = 0;
  BTNode<Integer>[] stack = new BTNode[1];
  int p = 0;
  BTNode<Integer> node = root;
  for (;;) {
    if (node.left == null) {
      if (node.right == null) {
        if (p == 0) break;
        node = stack[--p];
      } else { // node.right != null
        ++nonLeafCount;
        node = node.right;
      }
    } else { // node.left != null
      ++nonLeafCount;
      if (node.right != null) {
        if (p >= stack.length) {
          stack = Arrays.copyOf(stack, 2 * stack.length);
        }
        stack[p++] = node.right;
      }
      node = node.left;
    }
  }
  return nonLeafCount;
}

You can see that to eek out a tiny bit of efficiency we lose a lot of simplicity. This is almost always a bad bargain. I recommend against it.

Gene
  • 46,253
  • 4
  • 58
  • 96
  • Thank you, this works however I will need to go look at this now to thoroughly understand it. If you can answer some questions that will be great. – bob9123 Feb 11 '16 at 01:14
  • What exactly is going on this line ' if (p + 1 >= stack.length) stack = Arrays.copyOf(stack, 2 * stack.length);' – bob9123 Feb 11 '16 at 01:32
  • It's making sure the stack has at least 2 free elements to push the new children and growing the stack if not. Look up the javadoc for `Arrays.copyOf`. If you were allowed to use a Stack class, this would be taken care of behind the scenes. – Gene Feb 11 '16 at 01:34
  • Honestly, the Morris' algorithm was something I was looking for but I just couldn't get the logic right 100% to do it myself. – bob9123 Feb 11 '16 at 01:45
  • If I wanted to change this method and find the deepest node (root to deepest leaf) will this code help too? Will I have to put everything on the stack /pop and keep track of the deepest path? – bob9123 Feb 11 '16 at 01:49
  • You will have to make the stack into a stack of pairs. Each pair contains a node and its depth. The first pair pushed on the stack is [root, 1]. When you push children on the stack, the pair contains the child and 1+the depth of its parent. In place of the non-leaf counter, track the max depth of any pair popped off the stack. – Gene Feb 11 '16 at 02:06
  • Ah I understand most of this. Can you give a quick example on how I would implement a stack of pairs quickly please? – bob9123 Feb 11 '16 at 02:12
  • Thank you very much Gene.I understand how to do this. Now one last thing, I don't want to you type the code for this, you've helped me out too much already and I don't want to use all your time ha. If I wanted to search the tree see if a specific integer is there could the nonleaves method help me as that iterates through the whole tree? What will be the best way to do it? – bob9123 Feb 11 '16 at 19:59
  • @bob9123 Sure. It's a loop that you can stop at any iteration! When you find the node you're searching for, just return it immediately. It would be a waste to keep searching. – Gene Feb 12 '16 at 23:26
  • Incidentally, if you like the answer, you should accept it. That's how SO works. – Gene Feb 12 '16 at 23:26
0

A possible solution:

public class BST<T> {
    public BTNode<T> root;
    int depthCount = 0;

    public BST() {
        root = null;
    }

    public int nonleaves() { // Method must be declared like this. No
                                // parameters.
        BTNode<T> current = root;
        BTNode<T> previous = null;
        int nonLeafCount = 0;

        while (current != null) {
            if (previous == current.parent) { // this includes when parent is
                                                // null, i.e. current is the
                                                // root.
                previous = current;
                if (current.left != null) {
                    nonLeafCount++;
                    current = current.left;
                } else if (current.right != null) {
                    nonLeafCount++;
                    current = current.right;
                } else {
                    current = current.parent;
                }
            } else if (previous == current.left) {
                previous = current;
                if (current.right != null) {
                    current = current.right;
                } else {
                    current = current.parent;
                }
            } else {
                // previous==current.right
                previous = current;
                current = current.parent;
            }
        }
        return nonLeafCount;
    }

    private static class BTNode<T> {
        BTNode<T> left, right, parent;

        /* ... */
    }
}

Using stacks:

public class BST2<T> {
    public BTNode<T> root;
    int depthCount = 0;

    public BST2() {
        root = null;
    }

    public int nonleaves() { // Method must be declared like this. No
                                // parameters.
        BTNode<T> current = root;
        BTNode<T> previous = null;
        int nonLeafCount = 0;

        MyStack myStack = new MyStack(); // New empty stack

        while (current != null) {
            if (previous == myStack.top()) { // this includes when stack is 
                                                // empty, i.e. current is the
                                                // root.
                myStack.push(current);
                previous = current;
                if (current.left != null) {
                    nonLeafCount++;
                    current = current.left;
                } else if (current.right != null) {
                    nonLeafCount++;
                    current = current.right;
                } else {
                    myStack.pop();
                    current = myStack.top();
                }
            } else if (previous == current.left) {
                previous = current;
                if (current.right != null) {
                    current = current.right;
                } else {
                    myStack.pop();
                    current = myStack.top();
                }
            } else {
                // previous==current.right
                previous = current;
                myStack.pop();
                current = myStack.top();
            }
        }
        return nonLeafCount;
    }

    private static class BTNode<T> {
        BTNode<T> left, right;

        /* ... */
    }
}
beibichunai
  • 130
  • 1
  • 10
  • My main problem is that I'm not sure how to go back 'up' the tree. When I get to a leaf how do I go back to the node? I tried using previous variable etc but still couldn't figure it out. – bob9123 Feb 09 '16 at 18:49
  • Understood, no way up. Then you have no way but to implement some kind of stack. It is easy to implement with arrays as posted above. – beibichunai Feb 09 '16 at 21:29
  • Let me amend my last comment. If you have made the tree definition and are allowed to change it, you can solve this exercise without using stacks, just adding a reference to the parent node. Otherwise you need a stack. – beibichunai Feb 10 '16 at 09:47
  • Reference to the parent node is the way I am trying to do. I just cannot get the logic right for it which is why I came here asking for help. – bob9123 Feb 10 '16 at 11:59
  • Ok, I'm editing my first post to add a solution. The 2 hints are not valid, I'm removing them. – beibichunai Feb 10 '16 at 22:48
  • Thanks for this. While testing it I always getting 1 as a result. Is depthCount variable supposed to be nonLeafCount variable? Also is there a way to do this without adding the parent instance variable in BTNode class? – bob9123 Feb 10 '16 at 23:22
  • I think it will return 1 because I have not implemented parent in my insert method. So it will always be null. – bob9123 Feb 10 '16 at 23:26
  • Okay thank you. I definitely will need to produce a stack. I cannot have any other variables in the BTNode class. What is the way to go about this for my scenario? Looking at Stack examples online it does not seem compatible with my work. – bob9123 Feb 10 '16 at 23:59
  • Oh, sorry, I have not tested this. The depthCount variable should be nonLeafCount instead. I'll fix this. I think if parent is always null this method will return the depth for the leftmost leaf node. As already posted, parent is needed to avoid using stacks. There is no way to implement but to use stacks or references to parents. – beibichunai Feb 11 '16 at 00:00
  • Will the myStack.top() just contain a reference the root of the BST? – bob9123 Feb 11 '16 at 00:43