COMP 212 Lab 11: Binary Trees and Binary Search Trees

Review & Overview

As in COMP 210, we can define binary trees of the form

Following COMP 212 ideas, we can define an immutable version, akin to AList, or an mutable version, akin to LRStruct. In class, we introduced the mutable version and called it BiTree.

Be aware of a confusing overlap in terminology. A tree is a collection of nodes, including the root node (or simply "root"), the interior nodes, and the leaf nodes (or simply "leaves"). Also, when using the state pattern, we have sometimes used the term node to refer to the class with a state field. So, for mutable lists, each tree-node really consists of a tree-classed object and a state-pattern-node-classed object. Confused yet?

By default, a binary tree is not necessarily balanced. I.e., all the paths from the root to leaves may be of arbitrary length.

As in COMP 210, we can consider a special kind of binary tree, called the binary search tree. It is organized such that, for each node, all the nodes to the left have lower-ordered data, and all the nodes to the right have high-ordered data. Again, binary search trees can be immutable or mutable. In class, we introduced the mutable version and called it BSTree.

Also as in COMP 210, there are many other variants of trees. One that we won't use in COMP 212 is worth at least a mention. If we want a tree with arbitrary branching, each tree node can have a list of child trees. Thus, we could have a tree class that also used a list class. If we chose mutable versions of each, we get two uses of the state pattern, and thus two distinct state-pattern-node-classes. Exercise: List the fields needed for these two classes in order to see that they are indeed different, and thus can't be combined.


Exercises

Write the following visitors on binary trees. (You probably won't have time for all of them.) Make any helper visitors be inner classes.

  1. LeftmostTreeFinder returns the leftmost non-empty subtree of the host (if any). If the host is empty, it returns the empty tree.

  2. InOrderEnumeration, which also implements Enumeration.

    As a reminder(?), an in-order enumeration of a binary tree first enumerates everything to the left, then enumerates the current node, then enumerates everything to the right.

    The only real "trick" is for your enumeration to remember what it has left to enumerate. E.g., you want to first enumerate the left branch, but how do you remember to enumerate the right branch when you're done with that? Hint: Let InorderEnumeration have a local stack field.

  3. PostOrderEnumeration, which also implements Enumeration.

    As a reminder(?), a post-order enumeration of a binary tree first enumerates everything to the left, then everything to the right, then the current node.

    Note that if you had a tree representing arithmetic expressions, a post-order listing of its contents would be a post-fix (RPN) expression.

  4. LeafCounter returns the count of the number of leaves in the tree. In this implementation, a leaf is a tree with empty left and right subtrees.

Solutions to some of these are here.