/* *_________________________________________________________________________* * POEMS: PARALLELIZABLE OPEN SOURCE EFFICIENT MULTIBODY SOFTWARE * * DESCRIPTION: SEE READ-ME * * FILE NAME: poemstree.h * * AUTHORS: See Author List * * GRANTS: See Grants List * * COPYRIGHT: (C) 2005 by Authors as listed in Author's List * * LICENSE: Please see License Agreement * * DOWNLOAD: Free at www.rpi.edu/~anderk5 * * ADMINISTRATOR: Prof. Kurt Anderson * * Computational Dynamics Lab * * Rensselaer Polytechnic Institute * * 110 8th St. Troy NY 12180 * * CONTACT: anderk5@rpi.edu * *_________________________________________________________________________*/ #ifndef TREE_H #define TREE_H #include "poemstreenode.h" #include "poemsnodelib.h" // constants to indicate the balance factor of a node const int leftheavy = -1; const int balanced = 0; const int rightheavy = 1; class Tree{ protected: // pointer to tree root and node most recently accessed TreeNode *root; TreeNode *current; // number of elements in the tree int size; // used by the copy constructor and assignment operator TreeNode *CopyTree(TreeNode *t); // callback function to delete aux data void (*DeleteAuxData)(void *); // used by insert and delete method to re-establish // the avl conditions after a node is added or deleted // from a subtree void SingleRotateLeft (TreeNode* &p); void SingleRotateRight (TreeNode* &p); void DoubleRotateLeft (TreeNode* &p); void DoubleRotateRight (TreeNode* &p); void UpdateLeftTree (TreeNode* &p, int &reviseBalanceFactor); void UpdateRightTree (TreeNode* &p, int &reviseBalanceFactor); // used by destructor, assignment operator and ClearList void DeleteTree(TreeNode *t); void ClearTree(TreeNode * &t); // locate a node with data item and its parent in tree // used by Find and Delete TreeNode *FindNode(const int& item, TreeNode* & parent) const; public: // constructor, destructor Tree(void); ~Tree(void) { ClearTree(root); }; // assignment operator Tree& operator= (const Tree& rhs); // standard list handling methods void * Find(int& item); void * GetAuxData(int item) { return (void *)(FindNode(item, root)->GetAuxData()); } void SetDeleteAuxData(void (*callback)(void *)) { DeleteAuxData = callback; } void Insert(const int& item, const int& data, void * AuxData = NULL); void Delete(const int& item); void AVLInsert(TreeNode* &tree, TreeNode* newNode, int &reviseBalanceFactor); void ClearList(void); // tree specific methods void Update(const int& item); TreeNode *GetRoot(void) const; }; // constructor Tree::Tree(void) { root = 0; current = 0; size = 0; DeleteAuxData = NULL; } // return root pointer TreeNode *Tree::GetRoot(void) const { return root; } // assignment operator Tree& Tree::operator = (const Tree& rhs) { // can't copy a tree to itself if (this == &rhs) return *this; // clear current tree. copy new tree into current object ClearList(); root = CopyTree(rhs.root); // assign current to root and set the tree size current = root; size = rhs.size; // return reference to current object return *this; } // search for data item in the tree. if found, return its node // address and a pointer to its parent; otherwise, return NULL TreeNode *Tree::FindNode(const int& item, TreeNode* & parent) const { // cycle t through the tree starting with root TreeNode *t = root; // the parent of the root is NULL parent = NULL; // terminate on empty subtree while(t != NULL) { // stop on a match if (item == t->data) break; else { // update the parent pointer and move right of left parent = t; if (item < t->data) t = t->left; else t = t->right; } } // return pointer to node; NULL if not found return t; } // search for item. if found, assign the node data to item void * Tree::Find(int& item) { // we use FindNode, which requires a parent parameter TreeNode *parent; // search tree for item. assign matching node to current current = FindNode (item, parent); // if item found, assign data to item and return True if (current != NULL) { item = current->data; return current->GetAuxData(); } else // item not found in the tree. return False return NULL; } void Tree::Insert(const int& item, const int& data, void * AuxData) { // declare AVL tree node pointer; using base class method // GetRoot. cast to larger node and assign root pointer TreeNode *treeRoot, *newNode; treeRoot = GetRoot(); // flag used by AVLInsert to rebalance nodes int reviseBalanceFactor = 0; // get a new AVL tree node with empty pointer fields newNode = GetTreeNode(item,NULL,NULL); newNode->data = data; newNode->SetAuxData(AuxData); // call recursive routine to actually insert the element AVLInsert(treeRoot, newNode, reviseBalanceFactor); // assign new values to data members in the base class root = treeRoot; current = newNode; size++; } void Tree::AVLInsert(TreeNode *&tree, TreeNode *newNode, int &reviseBalanceFactor) { // flag indicates change node's balanceFactor will occur int rebalanceCurrNode; // scan reaches an empty tree; time to insert the new node if (tree == NULL) { // update the parent to point at newNode tree = newNode; // assign balanceFactor = 0 to new node tree->balanceFactor = balanced; // broadcast message; balanceFactor value is modified reviseBalanceFactor = 1; } // recursively move left if new data < current data else if (newNode->data < tree->data) { AVLInsert(tree->left,newNode,rebalanceCurrNode); // check if balanceFactor must be updated. if (rebalanceCurrNode) { // went left from node that is left heavy. will // violate AVL condition; use rotation (case 3) if (tree->balanceFactor == leftheavy) UpdateLeftTree(tree,reviseBalanceFactor); // went left from balanced node. will create // node left on the left. AVL condition OK (case 1) else if (tree->balanceFactor == balanced) { tree->balanceFactor = leftheavy; reviseBalanceFactor = 1; } // went left from node that is right heavy. will // balance the node. AVL condition OK (case 2) else { tree->balanceFactor = balanced; reviseBalanceFactor = 0; } } else // no balancing occurs; do not ask previous nodes reviseBalanceFactor = 0; } // otherwise recursively move right else { AVLInsert(tree->right, newNode, rebalanceCurrNode); // check if balanceFactor must be updated. if (rebalanceCurrNode) { // went right from node that is left heavy. wil; // balance the node. AVL condition OK (case 2) if (tree->balanceFactor == leftheavy) { // scanning right subtree. node heavy on left. // the node will become balanced tree->balanceFactor = balanced; reviseBalanceFactor = 0; } // went right from balanced node. will create // node heavy on the right. AVL condition OK (case 1) else if (tree->balanceFactor == balanced) { // node is balanced; will become heavy on right tree->balanceFactor = rightheavy; reviseBalanceFactor = 1; } // went right from node that is right heavy. will // violate AVL condition; use rotation (case 3) else UpdateRightTree(tree, reviseBalanceFactor); } else reviseBalanceFactor = 0; } } void Tree::UpdateLeftTree (TreeNode* &p, int &reviseBalanceFactor) { TreeNode *lc; lc = p->Left(); // left subtree is also heavy if (lc->balanceFactor == leftheavy) { SingleRotateRight(p); reviseBalanceFactor = 0; } // is right subtree heavy? else if (lc->balanceFactor == rightheavy) { // make a double rotation DoubleRotateRight(p); // root is now balance reviseBalanceFactor = 0; } } void Tree::UpdateRightTree (TreeNode* &p, int &reviseBalanceFactor) { TreeNode *lc; lc = p->Right(); // right subtree is also heavy if (lc->balanceFactor == rightheavy) { SingleRotateLeft(p); reviseBalanceFactor = 0; } // is left subtree heavy? else if (lc->balanceFactor == leftheavy) { // make a double rotation DoubleRotateLeft(p); // root is now balance reviseBalanceFactor = 0; } } void Tree::SingleRotateRight (TreeNode* &p) { // the left subtree of p is heavy TreeNode *lc; // assign the left subtree to lc lc = p->Left(); // update the balance factor for parent and left child p->balanceFactor = balanced; lc->balanceFactor = balanced; // any right subtree st of lc must continue as right // subtree of lc. do by making it a left subtree of p p->left = lc->Right(); // rotate p (larger node) into right subtree of lc // make lc the pivot node lc->right = p; p = lc; } void Tree::SingleRotateLeft (TreeNode* &p) { // the right subtree of p is heavy TreeNode *lc; // assign the left subtree to lc lc = p->Right(); // update the balance factor for parent and left child p->balanceFactor = balanced; lc->balanceFactor = balanced; // any right subtree st of lc must continue as right // subtree of lc. do by making it a left subtree of p p->right = lc->Left(); // rotate p (larger node) into right subtree of lc // make lc the pivot node lc->left = p; p = lc; } // double rotation right about node p void Tree::DoubleRotateRight (TreeNode* &p) { // two subtrees that are rotated TreeNode *lc, *np; // in the tree, node(lc) <= node(np) < node(p) lc = p->Left(); // lc is left child of parent np = lc->Right(); // np is right child of lc // update balance factors for p, lc, and np if (np->balanceFactor == rightheavy) { p->balanceFactor = balanced; lc->balanceFactor = rightheavy; } else if (np->balanceFactor == balanced) { p->balanceFactor = balanced; lc->balanceFactor = balanced; } else { p->balanceFactor = rightheavy; lc->balanceFactor = balanced; } np->balanceFactor = balanced; // before np replaces the parent p, take care of subtrees // detach old children and attach new children lc->right = np->Left(); np->left = lc; p->left = np->Right(); np->right = p; p = np; } void Tree::DoubleRotateLeft (TreeNode* &p) { // two subtrees that are rotated TreeNode *lc, *np; // in the tree, node(lc) <= node(np) < node(p) lc = p->Right(); // lc is right child of parent np = lc->Left(); // np is left child of lc // update balance factors for p, lc, and np if (np->balanceFactor == leftheavy) { p->balanceFactor = balanced; lc->balanceFactor = leftheavy; } else if (np->balanceFactor == balanced) { p->balanceFactor = balanced; lc->balanceFactor = balanced; } else { p->balanceFactor = leftheavy; lc->balanceFactor = balanced; } np->balanceFactor = balanced; // before np replaces the parent p, take care of subtrees // detach old children and attach new children lc->left = np->Right(); np->right = lc; p->right = np->Left(); np->left = p; p = np; } // if item is in the tree, delete it void Tree::Delete(const int& item) { // DNodePtr = pointer to node D that is deleted // PNodePtr = pointer to parent P of node D // RNodePtr = pointer to node R that replaces D TreeNode *DNodePtr, *PNodePtr, *RNodePtr; // search for a node containing data value item. obtain its // node adress and that of its parent if ((DNodePtr = FindNode (item, PNodePtr)) == NULL) return; // If D has NULL pointer, the // replacement node is the one on the other branch if (DNodePtr->right == NULL) RNodePtr = DNodePtr->left; else if (DNodePtr->left == NULL) RNodePtr = DNodePtr->right; // Both pointers of DNodePtr are non-NULL else { // Find and unlink replacement node for D // Starting on the left branch of node D, // find node whose data value is the largest of all // nodes whose values are less than the value in D // Unlink the node from the tree // PofRNodePtr = pointer to parent of replacement node TreeNode *PofRNodePtr = DNodePtr; // frist possible replacement is left child D RNodePtr = DNodePtr->left; // descend down right subtree of the left child of D // keeping a record of current node and its parent. // when we stop, we have found the replacement while (RNodePtr->right != NULL) { PofRNodePtr = RNodePtr; RNodePtr = RNodePtr; } if (PofRNodePtr == DNodePtr) // left child of deleted node is the replacement // assign right subtree of D to R RNodePtr->right = DNodePtr->right; else { // we moved at least one node down a right brance // delete replacement node from tree by assigning // its left branc to its parent PofRNodePtr->right = RNodePtr->left; // put replacement node in place of DNodePtr. RNodePtr->left = DNodePtr->left; RNodePtr->right = DNodePtr->right; } } // complete the link to the parent node // deleting the root node. assign new root if (PNodePtr == NULL) root = RNodePtr; // attach R to the correct branch of P else if (DNodePtr->data < PNodePtr->data) PNodePtr->left = RNodePtr; else PNodePtr->right = RNodePtr; // delete the node from memory and decrement list size FreeTreeNode(DNodePtr); // this says FirstTreeNode in the book, should be a typo size--; } // if current node is defined and its data value matches item, // assign node value to item; otherwise, insert item in tree void Tree::Update(const int& item) { if (current !=NULL && current->data == item) current->data = item; else Insert(item, item); } // create duplicate of tree t; return the new root TreeNode *Tree::CopyTree(TreeNode *t) { // variable newnode points at each new node that is // created by a call to GetTreeNode and later attached to // the new tree. newlptr and newrptr point to the child of // newnode and are passed as parameters to GetTreeNode TreeNode *newlptr, *newrptr, *newnode; // stop the recursive scan when we arrive at an empty tree if (t == NULL) return NULL; // CopyTree builds a new tree by scanning the nodes of t. // At each node in t, CopyTree checks for a left child. if // present it makes a copy of left child or returns NULL. // the algorithm similarly checks for a right child. // CopyTree builds a copy of node using GetTreeNode and // appends copy of left and right children to node. if (t->Left() !=NULL) newlptr = CopyTree(t->Left()); else newlptr = NULL; if (t->Right() !=NULL) newrptr = CopyTree(t->Right()); else newrptr = NULL; // Build new tree from the bottom up by building the two // children and then building the parent newnode = GetTreeNode(t->data, newlptr, newrptr); // return a pointer to the newly created node return newnode; } // us the postorder scanning algorithm to traverse the nodes in // the tree and delete each node as the vist operation void Tree::DeleteTree(TreeNode *t) { if (t != NULL) { DeleteTree(t->Left()); DeleteTree(t->Right()); void *aux = t->GetAuxData(); if (aux != NULL) { if (DeleteAuxData != NULL) { (*DeleteAuxData)(aux); } else { delete (TreeNode *) aux; } } FreeTreeNode(t); } } // call the function DeleteTree to deallocate the nodes. then // set the root pointer back to NULL void Tree::ClearTree(TreeNode * &t) { DeleteTree(t); t = NULL; // root now NULL } // delete all nodes in list void Tree::ClearList(void) { delete root; delete current; size = 0; } #endif