#ifndef TREE_LIBRARY_FUNCTIONS #define TREE_LIBRARY_FUNCTIONS #include #include #include #include #include #ifndef NULL #include #endif // NULL #include "d_tnode.h" // use tnode class using namespace std; // objects hold a formatted label string and the level,column // coordinates for a shadow tree node class tnodeShadow { public: string nodeValueStr; // formatted node value int level,column; tnodeShadow *left, *right; tnodeShadow () {} }; // create one of three binary trees with character data. // the argument n selects from tree 0 - tree 2 tnode *buildTree(int n); // inorder recursive output of the nodes in a binary tree. // output separator after each node value. default value // of separator is " " template void inorderOutput(tnode *t, const string& separator); // postorder recursive output of the nodes in a binary tree. // output separator after each node value. default value // of separator is " " template void postorderOutput(tnode *t, const string& separator); // traverse the tree level by level and output each node in a // binary tree. output separator after each node value. default value // of separator is " " template void levelorderOutput(tnode *t, const string& separator); // accumulate the number of leaf nodes in count template void countLeaf(tnode *t, int& count); // return the depth of the binary tree template int depth (tnode *t); // create copy of tree t and return a pointer to the new root template tnode *copyTree(tnode *t); // traverse the nodes in the binary tree and delete each node template void deleteTree(tnode *t); // delete all tree nodes using deleteTree() and then assign // t to be NULL template void clearTree(tnode * & t); // recursive inorder scan used to build the shadow tree template tnodeShadow *buildShadowTree(tnode *t, int level, int& column); // display a binary tree. output of a node value requires // no more than maxCharacters template void displayTree(tnode *t, int maxCharacters); // delete the nodes in the shadow tree void deleteShadowTree(tnodeShadow *t); tnode *buildTree(int n) { // 9 tnode pointers; points to the 9 items in the tree tnode *root, *b, *c, *d, *e, *f, *g, *h, *i; // parameter n specifies a tree in the range 0 - 2 switch(n) { // nodes d and e are leaf nodes case 0: d = new tnode ('D'); e = new tnode ('E'); b = new tnode ('B',(tnode *)NULL, d); c = new tnode ('C',e, (tnode *)NULL); root = new tnode ('A',b, c); break; // nodes g, h, i, and d are leaf nodes case 1: g = new tnode ('G'); h = new tnode ('H'); i = new tnode ('I'); d = new tnode ('D'); e = new tnode ('E',g, (tnode *)NULL); f = new tnode ('F',h, i); b = new tnode ('B',d, e); c = new tnode ('C',(tnode *)NULL, f); root = new tnode ('A',b, c); break; // nodes g, h, i and f are leaf nodes case 2: g = new tnode ('G'); h = new tnode ('H'); i = new tnode ('I'); d = new tnode ('D',(tnode *)NULL, g); e = new tnode ('E',h, i); f = new tnode ('F'); b = new tnode ('B',d, (tnode *)NULL); c = new tnode ('C',e, f); root = new tnode ('A',b, c); break; } return root; } template void inorderOutput(tnode *t, const string& separator = " ") { // the recursive scan terminates on a empty subtree if (t != NULL) { inorderOutput(t->left, separator); // descend left cout << t->nodeValue << separator; // output the node inorderOutput(t->right, separator); // descend right } } template void postorderOutput(tnode *t, const string& separator = " ") { // the recursive scan terminates on a empty subtree if (t != NULL) { postorderOutput(t->left, separator); // descend left postorderOutput(t->right, separator); // descend right cout << t->nodeValue << separator; // output the node } } template void levelorderOutput(tnode *t, const string& separator = " ") { // store siblings of each node in a queue so that they are // visited in order at the next level of the tree queue *> q; tnode *p; // initialize the queue by inserting the root in the queue q.push(t); // continue the iterative process until the queue is empty while(!q.empty()) { // delete front node from queue and output the node value p = q.front(); q.pop(); cout << p->nodeValue << separator; // if a left child exists, insert it in the queue if(p->left != NULL) q.push(p->left); // if a right child exists, insert next to its sibling if(p->right != NULL) q.push(p->right); } } // assume that count initialized to 0 template void countLeaf (tnode *t, int& count) { if (t != NULL) { // check if t is a leaf node (no children). // if so, increment count if (t->left == NULL && t->right == NULL) count++; countLeaf(t->left, count); // descend left countLeaf(t->right, count); // descend right } } // determine the depth of the tree using a postorder scan template int depth (tnode *t) { int depthLeft, depthRight, depthval; if (t == NULL) // depth of an empty tree is -1 depthval = -1; else { // find the depth of the left subtree of t depthLeft= depth(t->left); // find the depth of the right subtree of t depthRight= depth(t->right); // depth of the tree with root t is 1 + maximum // of the depths of the two subtrees depthval = 1 + (depthLeft > depthRight ? depthLeft : depthRight); } return depthval; } template tnode *copyTree(tnode *t) { // newNode points at a new node that the algorithm // creates. newLptr. and newRptr point to the subtrees // of newNode tnode *newLeft, *newRight, *newNode; // stop the recursive scan when we arrive at empty tree if (t == NULL) return NULL; // build the new tree from the bottom up by building the two // subtrees and then building the parent. at node t, make // a copy of the left subtree and assign its root node pointer // to newLeft. make a copy of the right subtree and assign its // root node pointer to newRight newLeft = copyTree(t->left); newRight = copyTree(t->right); // create a new node whose value is the same as the value in t // and whose children are the copied subtrees newNode = new tnode (t->nodeValue, newLeft, newRight); // return a pointer to the root of the newly copied tree return newNode; } template void deleteTree(tnode *t) { // postorder scan. delete left and right // subtrees of t and then node t if (t != NULL) { deleteTree(t->left); deleteTree(t->right); delete t; } } template void clearTree(tnode * & t) { deleteTree(t); t = NULL; } template tnodeShadow *buildShadowTree(tnode *t, int level, int& column) { // pointer to new shadow tree node tnodeShadow *newNode = NULL; // text and ostr used to perform format conversion char text[80]; ostrstream ostr(text,80); if (t != NULL) { // create the new shadow tree node newNode = new tnodeShadow; // allocate node for left child at next level in tree; attach node tnodeShadow *newLeft = buildShadowTree(t->left, level+1, column); newNode->left = newLeft; // initialize data members of the new node ostr << t->nodeValue << ends; // format conversion newNode->nodeValueStr = text; newNode->level = level; newNode->column = column; // update column to next cell in the table column++; // allocate node for right child at next level in tree; attach node tnodeShadow *newRight = buildShadowTree(t->right, level+1, column); newNode->right = newRight; } return newNode; } template void displayTree(tnode *t, int maxCharacters) { string label; int level = 0, column = 0; int colWidth = maxCharacters + 1; // int currLevel = 0, currCol = 0; if (t == NULL) return; // build the shadow tree tnodeShadow *shadowRoot = buildShadowTree(t, level, column); // use during the level order scan of the shadow tree tnodeShadow *currNode; // store siblings of each tnodeShadow object in a queue so that // they are visited in order at the next level of the tree queue q; // insert the root in the queue and set current level to 0 q.push(shadowRoot); // continue the iterative process until the queue is empty while(!q.empty()) { // delete front node from queue and make it the current node currNode = q.front(); q.pop(); // if level changes, output a newline if (currNode->level > currLevel) { currLevel = currNode->level; currCol = 0; cout << endl; } // if a left child exists, insert the child in the queue if(currNode->left != NULL) q.push(currNode->left); // if a right child exists, insert the child in the queue if(currNode->right != NULL) q.push(currNode->right); // output formatted node label if (currNode->column > currCol) { cout << setw((currNode->column-currCol)*colWidth) << " "; currCol = currNode->column; } cout << setw(colWidth) << currNode->nodeValueStr; currCol++; } cout << endl; // delete the shadow tree deleteShadowTree(shadowRoot); } void deleteShadowTree(tnodeShadow *t) { // if current root node is not NULL, delete its left subtree, // its right subtree and then the node itself if (t != NULL) { deleteShadowTree(t->left); deleteShadowTree(t->right); delete t; } } #endif // TREE_LIBRARY_FUNCTIONS