#include #include #include #include "bst.h" Node::Node( Element d ) : data( d ) , left( NULL ) , right( NULL ) {} Node::Node( Element d, Node *l, Node *r ) : data( d ) , left( l ) , right( r ) {} BinarySearchTree::BinarySearchTree() : root( NULL ) , size( 0 ) {} BinarySearchTree::BinarySearchTree( const BinarySearchTree& other ) : root( NULL ) , size( other.size ) { root = copyFrom( other.root ); } // Create a deep copy of a binary search tree recursively by // copying the subtrees. Node *BinarySearchTree::copyFrom( Node *node ) { if( node == NULL ) { return NULL; } else { return new Node( node->data, copyFrom( node->left ), copyFrom( node->right ) ); } } class Deleter : public TraversalFunction { public: virtual void visit( Node * node ); }; void Deleter::visit( Node *node ) { delete node; } BinarySearchTree::~BinarySearchTree() { // Note that deleting nodes _has_ to take place in a postorder // fashion, not preorder or inorder. Otherwise, you could reference // memory through dangling pointers! Deleter d; postorder( d ); } BinarySearchTree& BinarySearchTree::operator =( const BinarySearchTree& other ) { Deleter d; postorder( d ); size = other.size; root = copyFrom( other.root ); return *this; } int BinarySearchTree::getSize() { return size; } void BinarySearchTree::insert( Element item ) { root = insertFrom( root, item ); size++; } Node *BinarySearchTree::insertFrom( Node *cur, Element item ) { if( cur == NULL ) { return new Node( item ); } else if( item < cur->data ) { cur->left = insertFrom( cur->left, item ); } else if( item > cur->data ) { cur->right = insertFrom( cur->right, item ); } return cur; } void BinarySearchTree::remove( Element item ) { root = removeFrom( root, item ); size--; } Node *BinarySearchTree::removeFrom( Node *cur, Element item ) { if( cur == NULL ) { // This can only happen if the item wasn't in the tree // in the first place. return cur; } else if( item < cur->data ) { cur->left = removeFrom( cur->left, item ); return cur; } else if( item > cur->data ) { cur->right = removeFrom( cur->right, item ); return cur; } else { // We found the element to remove. Now comes the hard part. if( cur->left == NULL && cur->right == NULL ) { // No children, so just delete. delete cur; return NULL; } else if( cur->left == NULL ) { // Just a right child, return it as new tree Node *res = cur->right; delete cur; return res; } else if( cur->right == NULL ) { Node *res = cur->left; delete cur; return res; } else { // Uh oh - two children. Must do some work. // Get the successor to cur->data in the tree, i.e. the smallest // element of the right subtree. Element m = minFrom( cur->right ); // Eliminate cur->data by overwriting it... cur->data = m; // Now delete the successor from the right subtree. There // are faster ways to do this, I choose the simplest way cur->right = removeFrom( cur->right, m ); // And we're done. return cur; } } } Element BinarySearchTree::minFrom( Node *cur ) { if( cur->left == NULL ) { return cur->data; } else { return minFrom( cur->left ); } } bool BinarySearchTree::isInTree( Element item ) { return isInTreeFrom( root, item ); } bool BinarySearchTree::isInTreeFrom( Node *cur, Element item ) { if( cur == NULL ) { return false; } else if( item < cur->data ) { return isInTreeFrom( cur->left, item ); } else if( item > cur->data ) { return isInTreeFrom( cur->right, item ); } else { // Not < or >, must be == return true; } } void BinarySearchTree::preorder( TraversalFunction& func ) { preorderFrom( func, root ); } void BinarySearchTree::inorder( TraversalFunction& func ) { inorderFrom( func, root ); } void BinarySearchTree::postorder( TraversalFunction& func ) { postorderFrom( func, root ); } void BinarySearchTree::preorderFrom( TraversalFunction& func, Node *cur ) { if( cur != NULL ) { func.visit( cur ); preorderFrom( func, cur->left ); preorderFrom( func, cur->right ); } } void BinarySearchTree::inorderFrom( TraversalFunction& func, Node *cur ) { if( cur != NULL ) { inorderFrom( func, cur->left ); func.visit( cur ); inorderFrom( func, cur->right ); } } void BinarySearchTree::postorderFrom( TraversalFunction& func, Node *cur ) { if( cur != NULL ) { postorderFrom( func, cur->left ); postorderFrom( func, cur->right ); func.visit( cur ); } } void Printer::visit( Node *node ) { os << node->data << " "; } void BinarySearchTree::print( ostream& os ) { Printer p( os ); inorder( p ); } // // Everything below here is used by the "printNice" method. The goal // is to produce a "nice" printout of a binary search tree, i.e. a graphical // representation of the tree using ascii lines. This is actually a // somewhat challenging problem, as the complexity of the code that // implements it shows. If you want a juicy programming problem, try // implementing the "printNice" method without looking at my code. Or // even better, try implementing it with the root at the top and // the leaves pointing down, as I draw them in lecture. That's actually // even more difficult, I think. // // Because I don't expect this code to be reused and I didn't want to // spend too much time on it, there's a lot of ugly stuff in here. Sorry. // static inline int abs( int i ) { return (i<0) ? -i : i; } static inline int sign( int i ) { return (i<0) ? -1 : ((i>0) ? 1 : 0); } static void startLine( int offs[], int sz, ostream& os ) { for( int idx = 0; idx < sz - 1; ++idx ) { int ab = abs( offs[ idx ] ); bool bar = false; if( sign( offs[ idx ] ) < 0 ) { bar = true; } for( int jdx = 0; jdx < ab - 1; ++jdx ) { os << ' '; } os << (bar?'|':' '); } for( int jdx = 0; jdx < abs( offs[ sz - 1 ] ) - 1; ++jdx ) { os << ' '; } } void BinarySearchTree::printNice( ostream& os ) { int offs[ 1000 ]; if( root == NULL ) { os << "EMPTY TREE" << endl; } else { if( root->left == NULL && root->right == NULL ) { os << root->data << endl; } else { char buf[ 10 ]; sprintf( buf, "%d", root->data ); int len = strlen( buf ); offs[ 0 ] = len + 3; printNiceFrom( offs, 1, os, root->right, true ); if( root->right != NULL ) { startLine( offs, 1, os ); os << "|" << endl; } os << root->data << " -+" << endl; if( root->left != NULL ) { startLine( offs, 1, os ); os << "|" << endl; } offs[ 0 ] = -abs( offs[ 0 ] ); printNiceFrom( offs, 1, os, root->left, false ); } } } void BinarySearchTree::printNiceFrom( int offs[], int sz, ostream& os, Node *cur, bool isright ) { if( cur != NULL ) { if( cur->left == NULL && cur->right == NULL ) { startLine( offs, sz, os ); os << "+- " << cur->data << endl; } else { char buf[ 10 ]; sprintf( buf, "%d", cur->data ); int len = strlen( buf ); offs[ sz ] = len + 5; printNiceFrom( offs, sz + 1, os, cur->right, true ); if( cur->right != NULL ) { startLine( offs, sz + 1, os ); os << "|" << endl; } startLine( offs, sz, os ); os << "+- " << cur->data << " -+" << endl; if( isright ) { offs[ sz - 1 ] = -abs( offs[ sz - 1 ] ); } else { offs[ sz - 1 ] = abs( offs[ sz - 1 ] ); } if( cur->left != NULL ) { startLine( offs, sz + 1, os ); os << "|" << endl; } offs[ sz ] = -abs( offs[ sz ] ); printNiceFrom( offs, sz + 1, os, cur->left, false ); } } }