CPS 100 -- Spring 1997

Group Assignment: Trees

These problems provide practice with trees, recursion, and big-Oh


Assume the following declarations have been made struct Tnode { int info; Tnode * left,* right; Tnode(int val, Tnode * lbranch = 0, Tnode * rbranch = 0); }; Tnode::Tnode(int val, Tnode * lbranch, Tnode * rbranch) : info(val), left(lbranch), right(rbranch) {} The following function returns the height of a tree (for the problems here we're using 0 for the height of an empty tree -- in other words height is counting nodes rather than edges). int TreeHeight(Tnode * t) // postcondition: returns height of tree with root t { if (t == 0) { return 0; } else { return 1 + Max(TreeHeight(t->left),TreeHeight(t->right)); } } where the function Max returns the largest of its two integer parameters.

Tree Diameter

The diameter of a tree (sometimes called the width) is the number of nodes on the longest path between two leaves in the tree. The diagram below shows two trees each with diameter nine, the leaves that form the ends of a longest path are shaded (note that there is more than one path in each tree of length nine, but no path longer than nine nodes).

The diameter of a tree T is the largest of the following quantities:

This leads directly to the following code:

int TreeDiameter(Tnode * tree) // postcondition: returns diameter of tree { if (tree != 0) { int leftDiameter = TreeDiameter(tree->left); int rightDiameter = TreeDiameter(tree->right); int leftHeight = Height(tree->left); int rightHeight = Height(tree->right); // longest path through root int rootPath = leftHeight + rightHeight + 1; return Max(leftDiameter,Max(rightDiameter,rootPath)); } return 0; }

Write a recurrence relation for the running time of TreeDiameter. The solution is greater than O(n), what is the complexity of TreeDiameter?










It's possible to calculte the diameter in O(n) time. This requires calculating the diameter and height in a bottom up manner. Fill in the body of the function DoDiameter so that the postconditions are satisfied which will make the new TreeDiameter find the diameter in O(n) time.

int TreeDiameter(Tnode * tree) { int height,diameter; // only need diameter, height is dummy here DoDiameter(tree,height,diameter); return diameter; } void DoDiameter(Tnode * t, int & height, int & diameter) // postcondition: sets height to height of tree t, // sets diameter to diameter of t { if (t != 0 { int leftHeight,rightHeight; int leftDiameter, rightDiameter; } }

General Trees (4 points)

A tree in which each node can have an arbitray number of children, and in which each node stores an integer, can be implemented using the following declarations:

struct GTnode { int info; GTnode * child; // first child of node GTnode * sibling; // sibling of node GTnode(int val, GTnode * kid = 0, GTnode * sib = 0) : info(val), child(kid), sibling(sib) {} };

Write the routine TreeProduct whose header is given below. TreeProduct returns the product of all the values stored in the nodes of t. For example, it would return 12! = 479,001,600 for the tree diagrammed below. In the tree below, the solid arrows represent the connections using the declaration for GTnode given above, the dotted arrows represent the ``conceptual'' children for each node of the tree.

By definition, the value returned for an empty tree is zero.

int TreeProduct(GTnode * t) // postcondition: returns product of all nodes in t // returns 0 if t is empty

Search/Isomorphism (12 points)

Two binary search trees s and t are value equal if every value in s is in t and every value in t is in s. The shapes of the trees don't matter, the collection of values stored in s must be the same as the collection stored in t for trees to be value equal.

Part A (2 points)

Consider the functions below. If both s and t have n nodes, reason about the running time of IsValueEqual. Then describe how to determine if two trees are value equal in O(n) time.

bool InTree(const string & s, Tree * t) // postcondition: returns true if s in t, otherwise returns false { if (t != 0) { if (t->info == s) return true; return InTree(s, t->left) || InTree(s, t->right); } return false; } bool FirstInSecond(Tree * s, Tree * t) // postcondition: returns true if all values of s are in t // returns false otherwise { if (s != 0) { if (InTree(s->info,t)) { return FirstInSecond(s->left,t) && FirstInSecond(s->right,t); } return false; } return true; } bool IsValueEqual(Tree * s, Tree * t) // postcondition: returns true if s is value equal to t, // returns false otherwise { return FirstInSecond(s,t) && FirstInSecond(t,s); } Part B

Two binary trees s and t are equivalent if they have the same shape; the values stored in the nodes do not affect whether two trees are equivalent. In the diagram below, the tree in the middle is NOT equivalent to the other trees, but the tree on the right IS equivalent to the tree on the left.

Write a function IsEquivalent that returns true if its two tree parameters are equivalent and false otherwise. You must also give the big-Oh running time of your function with a justification.


Part C

Two trees s and t are isomorphic if s can be transformed into t by swapping left and right children of some of the nodes of s. The values in the nodes are NOT not important in determining isomorphism, only the shape is important. The trees below are isomorphic because if the children of the nodes A, B, and G in the tree on the left are swapped, the tree on the right is obtained.

Write a function IsIsomorphic that returns true if two trees are isomorphic. You must give the big-Oh complexity (in the average case) of your function with a justification.