// Computer Science 367, Section 3, Fall 1997 // Instructor: Michael Siff (siff@cs.wisc.edu) // // // FILE: bst.C // // // A binary search tree class template implemented with the binary tree // class template. // // INVARIANT for BST: // For a given node, its key is greater than all the keys appearing in // its left subtree and less than all the keys appearing in its right // subtree. #include #include #include #include // PRIVATE MEMBER FUNCTIONS (utilities) // ------------------------ template bool BST::_hasBSTP(BinaryTree >*t) const // Recursively checks to see if t has the binary search tree property. All // BSTs should have this property, but this is useful as a check to make // sure that insert and remove are working properly, particularly if there // are derived classes. { bool result = true; if (t != NULL) { result = false; BT *L = t->leftOf(); Key k = keyOf(t->valOf()); result = (L == NULL || ((keyOf(L->valOf()) < k) && _hasBSTP(L))); if (result) { BT *R = t->rightOf(); result = (R == NULL || ((k < keyOf(R->valOf())) && _hasBSTP(R))); } } return result; } template bool BST::_hasAVLP(BinaryTree >*t, size_t &ht) const // Recursively checks to see if t has the AVL property: each node has // subtrees of heights that differ by at most one. The height of external // leaves are considered to be zero, internal leaves one. The reference // parameter ht is updated to have the height of t if t has the AVL // property. { bool result=true; if (t == NULL) ht = 0; else { result = false; size_t lh, rh; if (_hasAVLP(t->leftOf(),lh)) if (_hasAVLP(t->rightOf(),rh)) { int b = rh - lh; if (b > -2 && b < 2) { result = true; ht = 1 + max(lh,rh); } } } return result; } template ostream& BST::printNode(ostream& os, BinaryTree > *t, ostream& (*outputItem)(ostream&,const Item&), ostream& (*outputKey)(ostream&,const Key&)) const // Output the value of one node to the os and return os { pair ikp = t->valOf(); os << "{"; outputItem(os, ikp.first) << ", "; outputKey(os, ikp.second) << "}"; return os ; } template void BST::indentedPrint(BinaryTree > *t, size_t n, ostream& (*outputItem)(ostream&,const Item&), ostream& (*outputKey)(ostream&,const Key&)) const // Output the tree to standard output in reverse in order and return os { if (t==NULL) return; if (t->rightOf()!=NULL) { indentedPrint(t->rightOf(), n+1, outputItem, outputKey); } // indent n levels for (size_t i=0; ileftOf()!=NULL) { indentedPrint(t->leftOf(), n+1, outputItem, outputKey); } } // PROTECTED MEMBER FUNCTIONS (utilities) // -------------------------- template BinaryTree > *BST::successor(BinaryTree > *node) const // Precondition: node is not NULL // Returns a pointer to the node that has the succeeding key to node; // returns NULL if node had the greatest key in the tree. { BT *t; if (node->rightOf()!= NULL) { t = node->rightOf(); while(t->leftOf() != NULL) t = t->leftOf(); } else { BT *p = node; for(t = node->parentOf(); t != NULL && p==t->rightOf(); p = t, t = t->parentOf()); } return t; } template BinaryTree > *BST::_search(BinaryTree > *t, const Key& k) const // If k is a key of a node in t then returns a a pointer to that node; // otherwise returns NULL. { BT *retPtr = t; if (t != NULL) { Key thisKey = keyOf(t->valOf()); if (k < thisKey) retPtr = _search(t->leftOf(), k); else if (thisKey < k) retPtr = _search(t->rightOf(), k); } // otherwise the keys are equal return retPtr; } template BinaryTree > *BST::_insert(const pair& ikp) // If the key of ikp is already a key of a node in this tree then NULL is // returned; otherwise, a pointer is returned to the new node added to the // tree (which is in accordance to the rules for a binary search tree). { BT *newNode = NULL; if (isEmpty()) { root = new BinaryTree >(ikp); newNode = root; } else { bool found=false; BT *t=root; Key k = keyOf(ikp); while(newNode == NULL && !found) { Key thisKey = keyOf(t->valOf()); if (thisKey == k) found = true; else if (k < thisKey) { if (t->leftOf() == NULL) { newNode = new BinaryTree >(ikp); t->setLeft(newNode); } else t = t->leftOf(); } else { if (t->rightOf() == NULL) { newNode = new BinaryTree >(ikp); t->setRight(newNode); } else t = t->rightOf(); } } } return newNode; } template void BST::_remove(BinaryTree > *p) { // there are two cases: // (0) if p has at most one child, move its child (if it has one) up // and delete p if (p->leftOf() == NULL || p->rightOf() == NULL) removeNode(p); // (1) if p has two children, // let q = p's successor, copy q's value to p, and delete q. // Note this works because q can have at most one child. else { BT *q = successor(p); p->setVal(q->valOf()); removeNode(q); } } template bool BST::isRightChild(BinaryTree > *node) const // Returns true iff node is the right child of its parent. (False if node // is the root.) { return (node != NULL && node != root && ((node->parentOf())->rightOf()==node)); } template BinaryTree > *BST::removeNode(BinaryTree > *node) // Precondition: node has at most one child. // Deletes a single node without affecting the rest of the tree. // Returns a pointer to the node that has "taken the place" of node or NULL // if node was a leaf. { assert(!isEmpty()); BT *returnNode; if (node==root) { if (node->leftOf() == NULL) root = node->rightOf(); else root = node->leftOf(); returnNode = root; } else if (node->leftOf() == NULL) { returnNode = node->rightOf(); if (isRightChild(node)) (node->parentOf())->setRight(returnNode); else (node->parentOf())->setLeft(returnNode); } else { returnNode = node->leftOf(); if (isRightChild(node)) (node->parentOf())->setRight(returnNode); else (node->parentOf())->setLeft(returnNode); } node->setLeft(NULL); node->setRight(NULL); delete node; return returnNode; } // Constructors // ------------ template BST::BST() // create an empty tree : root(NULL) { } template BST::BST(const BST& source) // copy constructor { root = new BinaryTree >(*(source.root)); } // Destructor // ---------- template BST::~BST() { delete root; root = NULL; } // Constant Member Functions // ------------------------- template bool BST::isEmpty() const { return (root == NULL); } template size_t BST::height() const { assert(!isEmpty()); return(root->height()); } template size_t BST::size() const { if (isEmpty()) return 0; else return(root->size()); } template bool BST::search(const Key& k, Item& returnVal) const { BT *p = _search(root, k); if (p != NULL) returnVal = itemOf(p->valOf()); return (p != NULL); } template bool BST::hasBSTP() const { return _hasBSTP(root); } template bool BST::hasAVLP() const { size_t dummy; return _hasAVLP(root,dummy); } template void BST::displayTree(ostream& (*outputItem)(ostream&,const Item&), ostream& (*outputKey)(ostream&,const Key&)) const { indentedPrint(root,0,outputItem,outputKey); } // Modification Member Functions // ----------------------------- template void BST::operator=(const BST& source) { *root = (*(source.root)); } template bool BST::insert(const Item& v, const Key& k) { return (_insert(pair(v, k)) != NULL); } template bool BST::remove(const Key& k) { BT *node = _search(root, k); if (node != NULL) _remove(node); return (node != NULL); }