|
A destructive function modifies a tree. For example, the following function replaces each item in tree t by its cube.
void cubeAll(Tree t) { if(t != NULL) { t->item = cube(t->item); cubeAll(t->left); cubeAll(t->right); } }
Observe that the definition of cubeAll does a preorder treversal of t.
Parameter t does not need to be passed by reference to cubeAll because cubeAll does not need to change what t points to. It only changes the items in the node that t points to. So cubeAll uses call by pointer (since type Tree is the same as Node*).
To change a tree t into its mirror image, it is just a matter of swapping left and right subtrees of the root of t, then changing each subtree of t into its mirror image. A base case for an empty tree is also important: to change an empty tree into its mirror image, do nothing.
// swapTrees(A,B) swaps the trees in variables A and B. void swapTrees(Tree& A, Tree& B) { Tree temp = A; A = B; B = temp; } // changeToMirror(t) changes tree t into its mirror // image. This is a destructive function: it modifies // the nodes in t. void changeToMirror(Tree t) { if(t != NULL) { swapTrees(t->left, t->right); changeToMirror(t->left); changeToMirror(t->right); }
Let's define function removeLeftmostNode(t), which changes tree t by removing the node that lies as far as to the left as possible from the root. For example, if t is
then, after removing the leftmost node, t is
and doing another step of removing the leftmost node yields
It is easy to find the lefmost node: just move to the left until a null left pointer is encountered. To remove leftmost node L, all we need to do is replace the left subtree of the parent of L with a the right subtree of L. That might sound tricky, since L does not contain a pointer to its parent. Indeed, if you use a loop, it is tricky. There is also another issue: if tree t has only one node, then instead of changing the left subtree of a node, we need to change t to hold NULL.)
But recursion handles both of those issues elegantly, so elegantly that you don't even notice them. Since t is passed by reference, it is the left pointer of the parent of t (or the pointer to the root if there is only one node). So it suffices to change t to be its right subtree, in the case where t's left subtree is empty.
We do need to handle the special case where t is empty; then there are no nodes, so we do nothing. Also, when a node is removed, it should be recycled back to the heap manager.
void removeLeftmostNode(Tree& t) { if(t != NULL) { if(t->left != NULL) { removeLeftmostNode(t->left); } else { Tree hold = t; t = t->right; delete hold; } } }
Is the definition of removeLeftmostNode tail recursive? Answer
Does the following correctly implement a nondestructive function to compute the mirror image of a tree?
Tree mirror(Tree t) { Tree cpy = t; changeToMirror(cpy); return cpy; }Answer
Write a definition of function destroy(T ), which deletes every node in tree T. Answer
|