// BinTree.h // A binary tree class using an embedded class for the nodes. // All code is implemented here in the .h file. // tom bailey 26 mar 01 #ifndef BINTREE_H_ #define BINTREE_H_ #include //*** Bin Tree class ***// class BinTree { protected: // Since the TreeNode class is embedded in the BinTree // class, the public data members and methods of // TreeNode are only visible within the BinTree class. // Client code cannot see TreeNode object data members // or methods. class TreeNode { public: short root; TreeNode * left; TreeNode * right; public: TreeNode( const short thisData = 0, TreeNode* thisLeft = NULL, TreeNode* thisRight = NULL ) : root( thisData ), left( thisLeft ), right( thisRight ) { } // The standard destructor code does NOT delete // TreeNodes in the subtrees of thisLeft or // thisRight. BinTree::destroy() follows the // branches to delete the entire tree. private: // Disable the copy constructor and the assignment // operator. TreeNode( const TreeNode & ); const TreeNode & operator =( const TreeNode & ); }; public: // The no-parameter constructor creates an empty tree. BinTree(); // The destructor deallocates all the nodes in the tree. ~BinTree(); // Build a randomly shaped tree of size nodes. Node // entries are successive shorts stored in the tree in // preorder. void build( long size, RanGen & rng ); // Display the tree. // The node values are listed using an inorder // traversal. // Node values are indented by the depth of the node to // display the shape of the tree. // The tree shape is displayed with the left subtree at // the top of the screen. void display( ostream& outfile ); // Several tree measures, special values, and traversals long size(); long height(); short leftmost(); long leaves(); void preorder( ostream & outfile ); private: TreeNode * treeptr; private: // Disable operator= BinTree& operator=( BinTree& ); // Disable the copy constructor BinTree( const BinTree & ); private: // helper functions // Each helper functions converts a request to process // the entire tree into a function that processes a // subtree referenced by a pointer to its root node. // The empty subtree is indicated by a NULL pointer. // Delete all nodes connected to treePtr static void destroy( TreeNode * treePtr ); // Build a random shaped tree of size nodes. The tree // data values start with entry. static void build( long size, RanGen & rng, TreeNode * & treePtr, short & entry ); // Display the nodes connected to treePtr on outfile. // This is a left subtree. // Use a line by line display, order nodes from left to // right, draw connecting lines. // Preface each line of the display with prefix. static void displayLeft( ostream & outfile, TreeNode * treePtr, string prefix ); // Display the nodes connected to treePtr on outfile. // This is a right subtree. // Use a line by line display, order nodes from left to // right, draw connecting lines. // Preface each line of the display with prefix. static void displayRight( ostream & outfile, TreeNode * treePtr, string prefix ); // Display the nodes connected to treePtr. // Use a line by line display, order nodes from left to // right, draw connecting lines. // Preface each line of the display with prefix. static void display( ostream & outfile, TreeNode * treePtr, string prefix ); // Return the number of nodes connected to treePtr. static long size( const TreeNode * treePtr ); // Return the height of the tree connected to treePtr. static long height( const TreeNode * treePtr ); // Return the value in the leftmost node connected to // treePtr. static short leftmost( const TreeNode * treePtr ); // Return the number of leaves in the tree connected to // treePtr. static long leaves( const TreeNode * treePtr ); // Write the values stored in the tree connected to // treePtr. Write the values to outfile. Write the // values in preorder. static void preorder( ostream & outfile, const TreeNode * treePtr ); }; // Code for public methods // The no-parameter constructor creates an empty tree. BinTree:: BinTree() : treeptr( NULL ) { } // The destructor deallocates all the nodes in the tree. BinTree:: ~BinTree() { destroy( treeptr ); } // BinTree methods // Each method is converted to a call to one of the helper // functions. The pointer to the tree root, treePtr, is // passed to the helper function as an additional // parameter. The additional parameter changes the // signature, so the same method/function name can be // used. // Build a randomly shaped tree of size nodes. // The first value entered will have to be redefined for any // non-numeric Object type. void BinTree:: build( long size, RanGen & rng ) { static short entry = 1; build( size, rng, treeptr, entry ); } // Display the tree. // The node values are ordered using an inorder traversal. // Node values are indented by the depth of the node to display // the shape of the tree. void BinTree:: display( ostream& outfile ) { string prefix; display( outfile, treeptr, prefix ); } long BinTree:: size() { return size( treeptr ); } long BinTree:: height() { return height( treeptr ); } short BinTree:: leftmost() { return leftmost( treeptr ); } long BinTree:: leaves() { return leaves( treeptr ); } void BinTree:: preorder( ostream & outfile ) { preorder( outfile, treeptr ); } // code for helper functions // Delete all nodes connected to treePtr void BinTree:: destroy( TreeNode * treePtr ) { if( treePtr != NULL ) { destroy( treePtr->left ); destroy( treePtr->right ); delete treePtr; treePtr = NULL; } } // Build a random shaped tree of size nodes. // Construct the TreeNodes in preorder sequence. void BinTree:: build( long size, RanGen & rng, TreeNode * & treePtr, short & entry ) { if( size == 0 ) { treePtr = NULL; } else { treePtr = new TreeNode( entry ); entry++; long leftSize = rng.randint( 0, size-1 ); build( leftSize, rng, treePtr->left, entry ); long rightSize = size - 1 - leftSize; build( rightSize, rng, treePtr->right, entry ); } } // Display the nodes connected to treePtr. // This is a left subtree. // Use a line by line display, order nodes from left to // right, draw connecting lines. void BinTree:: displayLeft( ostream & outfile, TreeNode * treePtr, string prefix ) { if( treePtr == NULL ) { outfile << prefix + "/" << endl; } else { displayLeft( outfile, treePtr->left, prefix + " " ); outfile << prefix + "/---" << treePtr->root << endl; displayRight( outfile, treePtr->right, prefix + "| " ); } } // Display the nodes connected to treePtr. // This is a right subtree. // Use a line by line display, order nodes from left to // right, draw connecting lines. void BinTree:: displayRight( ostream & outfile, TreeNode * treePtr, string prefix ) { if( treePtr == NULL ) { outfile << prefix + "\\" << endl; } else { displayLeft( outfile, treePtr->left, prefix + "| " ); outfile << prefix + "\\---" << treePtr->root << endl; displayRight( outfile, treePtr->right, prefix + " " ); } } // Display the nodes connected to treePtr. // Use a line by line display, order nodes from left to // right, draw connecting lines. void BinTree:: display( ostream & outfile, TreeNode * treePtr, string prefix ) { if( treePtr == NULL ) { outfile << prefix + "-" << endl; } else { displayLeft( outfile, treePtr->left, prefix + " " ); outfile << prefix + "---" << treePtr->root << endl; displayRight( outfile, treePtr->right, prefix + " " ); } } long BinTree:: size( const TreeNode * treePtr ) { return -1; } long BinTree:: height( const TreeNode * treePtr ) { return -2; } short BinTree:: leftmost( const TreeNode * treePtr ) { return -3; } long BinTree:: leaves( const TreeNode * treePtr ) { return -4; } void BinTree:: preorder( ostream & outfile, const TreeNode * treePtr ) { if( treePtr != NULL ) { outfile << treePtr->root << " "; preorder( outfile, treePtr->left ); preorder( outfile, treePtr->right ); } } #endif