Prelab 5

Straight Up Binary Trees
Due by 10am, Monday 8 Oct 2012

In this prelab, you will familiarize yourself with some of the design and implementation issues in the upcoming lab 5. Please write or type up your solutions, and hand in a paper copy before class on Monday. Remember, late prelabs receive zero credit.


Part 1 - Binary Trees

As you may recall from class, a binary tree is either:

  1. empty, or
  2. a root node of data with a left and right (sub)tree.

Therefore, you will have three classes:

  1. an abstract class BinaryTree<T> to represent any binary tree,
  2. a subclass EmptyTree<T> of BinaryTree<T> to represent any empty binary tree, and
  3. a subclass ConsTree<T> of BinaryTree<T> to represent any non-empty binary tree.
In this way, any binary tree you create will either be Empty or Cons. The EmptyTree class won't have any class variables, as there it is an empty structure. The ConsTree class, on the other hand, needs the following three class variables:

    private T	      	  data;
    private BinaryTree<T> left;
    private BinaryTree<T> right;
    

For each of the binary tree methods, you will do the following:

  1. add it as an abstract method to the BinaryTree class.
  2. implement the method in the EmptyTree class.
  3. implement the method in the ConsTree class.

For example, for the height method, you would:

  1. add the following to BinaryTree:
        public abstract int height( );
    
  2. add the following to EmptyTree:
        public int height( ) { return -1; }
    
  3. add the following to ConsTree:
        public int height( ) { 
    	return 1 + Math.max(left.height(),right.height()); 
        }
    

  1. Suppose you were to write an isLeaf method with the following header:
        public boolean isLeaf( )
        
    that returns whether the current binary tree is a single leaf node (that is, a tree with no left or right subtree). Write the method body for both the EmptyTree and ConsTree classes.






  2. Suppose you were to write a nodeCount method with the following header:
        public int nodeCount( ) 
        
    that returns the number of nodes / vertices in the tree. Write the method body for this method for both classes.






  3. Suppose you were to write a leafCount method with the following header:
        public int leafCount( )
        
    that returns the number of leaves in the tree. Write the method body for this method, presumably using calls to your isLeaf method. Write it for both classes.





  4. Suppose you were to write a mirrorImage method with the following header:
        public BinaryTree<T> mirrorImage()
        
    that returns a new tree which looks like the mirror image of the current tree (that is, a tree "flipped" around a vertical line through the root node). Write the method body for both classes.






  5. For the following tree, list the nodes as you would encounter them in a post-order, in-order, and pre-order.














An interesting problem is how you might implement the toString() method of a BinaryTree. I'll admit that I've not yet found a technique that I really like at this point. But collectively, you are more creative than I.

  1. Attempt to create some algorithm that could be used to convert your BinaryTree into a printable string. Note that I do not expect you to actually create a method for doing this, or even solving it, but I'd like to see what you come up with. One hint is that you may want to use a recursive helper method, that allows you to pass a parameter from one recursive call to the next (which the standard toString does not.)

Probably the trickiest method you will write is a method that reads in a binary tree from a file, and returns a new BinaryTree according to the file's contents. It should have the following method signature:

    public BinaryTree<String> loadFromFile(String filename)

The files in question will list the nodes of the tree in postorder sequence, one node per line. Each line contains a string, which is the data value stored in the node, and two tag bits. The first tag bit indicates whether or not this node has a left child or not. (1=oui,0=non). The second tag bit indicates whether the node has a right child or not.

For example, the tree













is represented as

    32 0 0
    74 0 1
    29 0 0
    63 1 0
    18 0 0
    83 1 1
    34 1 1

The information in the file is sufficient to uniquely determine a binary tree. The tree can be constructed from the file using the following pseudocode:


create an empty stack of binary trees (i.e. Stack<BinaryTree<String>>)
while there is another line of input in the file
    read a line (containing data and two tags)
    if right tag is 1, pop an element from the stack and call it right
    if left tag is 1, pop an element from the stack and call it left
    create a new binary tree with data as its root and
           left and right as its subtrees (if they exist)
    push the new tree onto your stack
when you exit the while loop, the stack should contain one element
this element is the the tree represented by the file data (so return it!)

NOTE: the input file is left then right, but the algorithm
uses the right value first, then the left. Not a typo.


  1. For the following input, run the algorithm above and output the resulting tree (that is, draw the resulting binary tree). Show your stack as you go through the algorithm (you can just draw small trees as elements as your stack). (You can check that you have the correct tree by running a post-order traversal on it. The nodes in post-order should correspond to the order from the file.)
  2.     E 0 0
        F 0 0
        D 1 1
        B 1 0
        C 0 0
        A 1 1