1 /*
2 *_________________________________________________________________________*
3 * POEMS: PARALLELIZABLE OPEN SOURCE EFFICIENT MULTIBODY SOFTWARE *
4 * DESCRIPTION: SEE READ-ME *
5 * FILE NAME: poemstree.h *
6 * AUTHORS: See Author List *
7 * GRANTS: See Grants List *
8 * COPYRIGHT: (C) 2005 by Authors as listed in Author's List *
9 * LICENSE: Please see License Agreement *
10 * DOWNLOAD: Free at www.rpi.edu/~anderk5 *
11 * ADMINISTRATOR: Prof. Kurt Anderson *
12 * Computational Dynamics Lab *
13 * Rensselaer Polytechnic Institute *
14 * 110 8th St. Troy NY 12180 *
15 * CONTACT: anderk5@rpi.edu *
16 *_________________________________________________________________________*/
17
18 #ifndef TREE_H
19 #define TREE_H
20
21 #include "poemstreenode.h"
22 #include "poemsnodelib.h"
23
24
25 // constants to indicate the balance factor of a node
26 const int leftheavy = -1;
27 const int balanced = 0;
28 const int rightheavy = 1;
29
30
31
32 class Tree{
33 protected:
34 // pointer to tree root and node most recently accessed
35 TreeNode *root;
36 TreeNode *current;
37
38 // number of elements in the tree
39 int size;
40 // used by the copy constructor and assignment operator
41 TreeNode *CopyTree(TreeNode *t);
42
43 // used by insert and delete method to re-establish
44 // the avl conditions after a node is added or deleted
45 // from a subtree
46 void SingleRotateLeft (TreeNode* &p);
47 void SingleRotateRight (TreeNode* &p);
48 void DoubleRotateLeft (TreeNode* &p);
49 void DoubleRotateRight (TreeNode* &p);
50 void UpdateLeftTree (TreeNode* &p, int &reviseBalanceFactor);
51 void UpdateRightTree (TreeNode* &p, int &reviseBalanceFactor);
52
53
54 // used by destructor, assignment operator and ClearList
55 void DeleteTree(TreeNode *t);
56 void ClearTree(TreeNode * &t);
57
58 // locate a node with data item and its parent in tree
59 // used by Find and Delete
60 TreeNode *FindNode(const int& item, TreeNode* & parent) const;
61
62 public:
63 // constructor, destructor
64 Tree(void);
~Tree(void)65 ~Tree(void)
66 {
67 ClearTree(root);
68 };
69
70 // assignment operator
71 Tree& operator= (const Tree& rhs);
72
73 // standard list handling methods
74 void * Find(int& item);
GetAuxData(int item)75 void * GetAuxData(int item) { return (void *)(FindNode(item, root)->GetAuxData());}
76 void Insert(const int& item, const int& data, void * AuxData = NULL);
77 void Delete(const int& item);
78 void AVLInsert(TreeNode* &tree, TreeNode* newNode, int &reviseBalanceFactor);
79 void ClearList(void);
80
81 // tree specific methods
82 void Update(const int& item);
83 TreeNode *GetRoot(void) const;
84 };
85
86
87 // constructor
Tree(void)88 Tree::Tree(void)
89 {
90 root = 0;
91 current = 0;
92 size = 0;
93 }
94
95
96
97 // return root pointer
GetRoot(void)98 TreeNode *Tree::GetRoot(void) const
99 {
100 return root;
101 }
102
103
104 // assignment operator
105 Tree& Tree::operator = (const Tree& rhs)
106 {
107 // can't copy a tree to itself
108 if (this == &rhs)
109 return *this;
110
111 // clear current tree. copy new tree into current object
112 ClearList();
113 root = CopyTree(rhs.root);
114
115 // assign current to root and set the tree size
116 current = root;
117 size = rhs.size;
118
119 // return reference to current object
120 return *this;
121 }
122
123 // search for data item in the tree. if found, return its node
124 // address and a pointer to its parent; otherwise, return NULL
FindNode(const int & item,TreeNode * & parent)125 TreeNode *Tree::FindNode(const int& item,TreeNode* & parent) const
126 {
127 // cycle t through the tree starting with root
128 TreeNode *t = root;
129
130 // the parent of the root is NULL
131 parent = NULL;
132
133 // terminate on empty subtree
134 while(t != NULL)
135 {
136 // stop on a match
137 if (item == t->data)
138 break;
139 else
140 {
141 // update the parent pointer and move right of left
142 parent = t;
143 if (item < t->data)
144 t = t->left;
145 else
146 t = t->right;
147 }
148 }
149
150 // return pointer to node; NULL if not found
151 return t;
152 }
153
154 // search for item. if found, assign the node data to item
Find(int & item)155 void * Tree::Find(int& item)
156 {
157 // we use FindNode, which requires a parent parameter
158 TreeNode *parent;
159
160 // search tree for item. assign matching node to current
161 current = FindNode (item, parent);
162
163 // if item found, assign data to item and return True
164 if (current != NULL)
165 {
166 item = current->data;
167 return current->GetAuxData();
168 }
169 else
170 // item not found in the tree. return False
171 return NULL;
172 }
173
174
Insert(const int & item,const int & data,void * AuxData)175 void Tree::Insert(const int& item, const int& data, void * AuxData)
176 {
177 // declare AVL tree node pointer; using base class method
178 // GetRoot. cast to larger node and assign root pointer
179 TreeNode *treeRoot, *newNode;
180 treeRoot = GetRoot();
181
182 // flag used by AVLInsert to rebalance nodes
183 int reviseBalanceFactor = 0;
184
185 // get a new AVL tree node with empty pointer fields
186 newNode = GetTreeNode(item,NULL,NULL);
187 newNode->data = data;
188 newNode->SetAuxData(AuxData);
189 // call recursive routine to actually insert the element
190 AVLInsert(treeRoot, newNode, reviseBalanceFactor);
191
192 // assign new values to data members in the base class
193 root = treeRoot;
194 current = newNode;
195 size++;
196
197 }
198
AVLInsert(TreeNode * & tree,TreeNode * newNode,int & reviseBalanceFactor)199 void Tree::AVLInsert(TreeNode *&tree, TreeNode *newNode, int &reviseBalanceFactor)
200 {
201 // flag indicates change node's balanceFactor will occur
202 int rebalanceCurrNode;
203
204 // scan reaches an empty tree; time to insert the new node
205 if (tree == NULL)
206 {
207 // update the parent to point at newNode
208 tree = newNode;
209
210 // assign balanceFactor = 0 to new node
211 tree->balanceFactor = balanced;
212 // broadcast message; balanceFactor value is modified
213 reviseBalanceFactor = 1;
214 }
215 // recursively move left if new data < current data
216 else if (newNode->data < tree->data)
217 {
218 AVLInsert(tree->left,newNode,rebalanceCurrNode);
219 // check if balanceFactor must be updated.
220 if (rebalanceCurrNode)
221 {
222 // went left from node that is left heavy. will
223 // violate AVL condition; use rotation (case 3)
224 if (tree->balanceFactor == leftheavy)
225 UpdateLeftTree(tree,reviseBalanceFactor);
226
227 // went left from balanced node. will create
228 // node left on the left. AVL condition OK (case 1)
229 else if (tree->balanceFactor == balanced)
230 {
231 tree->balanceFactor = leftheavy;
232 reviseBalanceFactor = 1;
233 }
234 // went left from node that is right heavy. will
235 // balance the node. AVL condition OK (case 2)
236 else
237 {
238 tree->balanceFactor = balanced;
239 reviseBalanceFactor = 0;
240 }
241 }
242 else
243 // no balancing occurs; do not ask previous nodes
244 reviseBalanceFactor = 0;
245 }
246 // otherwise recursively move right
247 else
248 {
249 AVLInsert(tree->right, newNode, rebalanceCurrNode);
250 // check if balanceFactor must be updated.
251 if (rebalanceCurrNode)
252 {
253 // went right from node that is left heavy. wil;
254 // balance the node. AVL condition OK (case 2)
255 if (tree->balanceFactor == leftheavy)
256 {
257 // scanning right subtree. node heavy on left.
258 // the node will become balanced
259 tree->balanceFactor = balanced;
260 reviseBalanceFactor = 0;
261 }
262 // went right from balanced node. will create
263 // node heavy on the right. AVL condition OK (case 1)
264 else if (tree->balanceFactor == balanced)
265 {
266 // node is balanced; will become heavy on right
267 tree->balanceFactor = rightheavy;
268 reviseBalanceFactor = 1;
269 }
270 // went right from node that is right heavy. will
271 // violate AVL condition; use rotation (case 3)
272 else
273 UpdateRightTree(tree, reviseBalanceFactor);
274 }
275 else
276 reviseBalanceFactor = 0;
277 }
278 }
279
280
UpdateLeftTree(TreeNode * & p,int & reviseBalanceFactor)281 void Tree::UpdateLeftTree (TreeNode* &p, int &reviseBalanceFactor)
282 {
283 TreeNode *lc;
284
285 lc = p->Left(); // left subtree is also heavy
286 if (lc->balanceFactor == leftheavy)
287 {
288 SingleRotateRight(p);
289 reviseBalanceFactor = 0;
290 }
291 // is right subtree heavy?
292 else if (lc->balanceFactor == rightheavy)
293 {
294 // make a double rotation
295 DoubleRotateRight(p);
296 // root is now balance
297 reviseBalanceFactor = 0;
298 }
299 }
300
UpdateRightTree(TreeNode * & p,int & reviseBalanceFactor)301 void Tree::UpdateRightTree (TreeNode* &p, int &reviseBalanceFactor)
302 {
303 TreeNode *lc;
304
305 lc = p->Right(); // right subtree is also heavy
306 if (lc->balanceFactor == rightheavy)
307 {
308 SingleRotateLeft(p);
309 reviseBalanceFactor = 0;
310 }
311 // is left subtree heavy?
312 else if (lc->balanceFactor == leftheavy)
313 {
314 // make a double rotation
315 DoubleRotateLeft(p);
316 // root is now balance
317 reviseBalanceFactor = 0;
318 }
319 }
320
SingleRotateRight(TreeNode * & p)321 void Tree::SingleRotateRight (TreeNode* &p)
322 {
323 // the left subtree of p is heavy
324 TreeNode *lc;
325
326 // assign the left subtree to lc
327 lc = p->Left();
328
329 // update the balance factor for parent and left child
330 p->balanceFactor = balanced;
331 lc->balanceFactor = balanced;
332
333 // any right subtree st of lc must continue as right
334 // subtree of lc. do by making it a left subtree of p
335 p->left = lc->Right();
336
337 // rotate p (larger node) into right subtree of lc
338 // make lc the pivot node
339 lc->right = p;
340 p = lc;
341 }
342
SingleRotateLeft(TreeNode * & p)343 void Tree::SingleRotateLeft (TreeNode* &p)
344 {
345 // the right subtree of p is heavy
346 TreeNode *lc;
347
348 // assign the left subtree to lc
349 lc = p->Right();
350
351 // update the balance factor for parent and left child
352 p->balanceFactor = balanced;
353 lc->balanceFactor = balanced;
354
355 // any right subtree st of lc must continue as right
356 // subtree of lc. do by making it a left subtree of p
357 p->right = lc->Left();
358
359 // rotate p (larger node) into right subtree of lc
360 // make lc the pivot node
361 lc->left = p;
362 p = lc;
363 }
364
365 // double rotation right about node p
DoubleRotateRight(TreeNode * & p)366 void Tree::DoubleRotateRight (TreeNode* &p)
367 {
368 // two subtrees that are rotated
369 TreeNode *lc, *np;
370
371 // in the tree, node(lc) <= node(np) < node(p)
372 lc = p->Left(); // lc is left child of parent
373 np = lc->Right(); // np is right child of lc
374
375 // update balance factors for p, lc, and np
376 if (np->balanceFactor == rightheavy)
377 {
378 p->balanceFactor = balanced;
379 lc->balanceFactor = rightheavy;
380 }
381 else if (np->balanceFactor == balanced)
382 {
383 p->balanceFactor = balanced;
384 lc->balanceFactor = balanced;
385 }
386 else
387 {
388 p->balanceFactor = rightheavy;
389 lc->balanceFactor = balanced;
390 }
391 np->balanceFactor = balanced;
392
393 // before np replaces the parent p, take care of subtrees
394 // detach old children and attach new children
395 lc->right = np->Left();
396 np->left = lc;
397 p->left = np->Right();
398 np->right = p;
399 p = np;
400 }
401
DoubleRotateLeft(TreeNode * & p)402 void Tree::DoubleRotateLeft (TreeNode* &p)
403 {
404 // two subtrees that are rotated
405 TreeNode *lc, *np;
406
407 // in the tree, node(lc) <= node(np) < node(p)
408 lc = p->Right(); // lc is right child of parent
409 np = lc->Left(); // np is left child of lc
410
411 // update balance factors for p, lc, and np
412 if (np->balanceFactor == leftheavy)
413 {
414 p->balanceFactor = balanced;
415 lc->balanceFactor = leftheavy;
416 }
417 else if (np->balanceFactor == balanced)
418 {
419 p->balanceFactor = balanced;
420 lc->balanceFactor = balanced;
421 }
422 else
423 {
424 p->balanceFactor = leftheavy;
425 lc->balanceFactor = balanced;
426 }
427 np->balanceFactor = balanced;
428
429 // before np replaces the parent p, take care of subtrees
430 // detach old children and attach new children
431 lc->left = np->Right();
432 np->right = lc;
433 p->right = np->Left();
434 np->left = p;
435 p = np;
436 }
437
438 // if item is in the tree, delete it
Delete(const int & item)439 void Tree::Delete(const int& item)
440 {
441 // DNodePtr = pointer to node D that is deleted
442 // PNodePtr = pointer to parent P of node D
443 // RNodePtr = pointer to node R that replaces D
444 TreeNode *DNodePtr, *PNodePtr, *RNodePtr;
445
446 // search for a node containing data value item. obtain its
447 // node adress and that of its parent
448 if ((DNodePtr = FindNode (item, PNodePtr)) == NULL)
449 return;
450
451 // If D has NULL pointer, the
452 // replacement node is the one on the other branch
453 if (DNodePtr->right == NULL)
454 RNodePtr = DNodePtr->left;
455 else if (DNodePtr->left == NULL)
456 RNodePtr = DNodePtr->right;
457 // Both pointers of DNodePtr are non-NULL
458 else
459 {
460 // Find and unlink replacement node for D
461 // Starting on the left branch of node D,
462 // find node whose data value is the largest of all
463 // nodes whose values are less than the value in D
464 // Unlink the node from the tree
465
466 // PofRNodePtr = pointer to parent of replacement node
467 TreeNode *PofRNodePtr = DNodePtr;
468
469 // frist possible replacement is left child D
470 RNodePtr = DNodePtr->left;
471
472 // descend down right subtree of the left child of D
473 // keeping a record of current node and its parent.
474 // when we stop, we have found the replacement
475 while (RNodePtr->right != NULL)
476 {
477 PofRNodePtr = RNodePtr;
478 RNodePtr = RNodePtr;
479 }
480
481 if (PofRNodePtr == DNodePtr)
482 // left child of deleted node is the replacement
483 // assign right subtree of D to R
484 RNodePtr->right = DNodePtr->right;
485 else
486 {
487 // we moved at least one node down a right brance
488 // delete replacement node from tree by assigning
489 // its left branc to its parent
490 PofRNodePtr->right = RNodePtr->left;
491
492 // put replacement node in place of DNodePtr.
493 RNodePtr->left = DNodePtr->left;
494 RNodePtr->right = DNodePtr->right;
495 }
496 }
497
498 // complete the link to the parent node
499 // deleting the root node. assign new root
500 if (PNodePtr == NULL)
501 root = RNodePtr;
502 // attach R to the correct branch of P
503 else if (DNodePtr->data < PNodePtr->data)
504 PNodePtr->left = RNodePtr;
505 else
506 PNodePtr->right = RNodePtr;
507
508 // delete the node from memory and decrement list size
509 FreeTreeNode(DNodePtr); // this says FirstTreeNode in the book, should be a typo
510 size--;
511 }
512
513
514
515
516
517 // if current node is defined and its data value matches item,
518 // assign node value to item; otherwise, insert item in tree
Update(const int & item)519 void Tree::Update(const int& item)
520 {
521 if (current !=NULL && current->data == item)
522 current->data = item;
523 else
524 Insert(item, item);
525 }
526
527 // create duplicate of tree t; return the new root
CopyTree(TreeNode * t)528 TreeNode *Tree::CopyTree(TreeNode *t)
529 {
530 // variable newnode points at each new node that is
531 // created by a call to GetTreeNode and later attached to
532 // the new tree. newlptr and newrptr point to the child of
533 // newnode and are passed as parameters to GetTreeNode
534 TreeNode *newlptr, *newrptr, *newnode;
535
536 // stop the recursive scan when we arrive at an empty tree
537 if (t == NULL)
538 return NULL;
539
540 // CopyTree builds a new tree by scanning the nodes of t.
541 // At each node in t, CopyTree checks for a left child. if
542 // present it makes a copy of left child or returns NULL.
543 // the algorithm similarly checks for a right child.
544 // CopyTree builds a copy of node using GetTreeNode and
545 // appends copy of left and right children to node.
546
547 if (t->Left() !=NULL)
548 newlptr = CopyTree(t->Left());
549 else
550 newlptr = NULL;
551
552 if (t->Right() !=NULL)
553 newrptr = CopyTree(t->Right());
554 else
555 newrptr = NULL;
556
557
558 // Build new tree from the bottom up by building the two
559 // children and then building the parent
560 newnode = GetTreeNode(t->data, newlptr, newrptr);
561
562 // return a pointer to the newly created node
563 return newnode;
564 }
565
566
567 // us the postorder scanning algorithm to traverse the nodes in
568 // the tree and delete each node as the vist operation
DeleteTree(TreeNode * t)569 void Tree::DeleteTree(TreeNode *t)
570 {
571 if (t != NULL)
572 {
573 DeleteTree(t->Left());
574 DeleteTree(t->Right());
575 if (t->GetAuxData() != NULL)
576 delete (TreeNode *) t->GetAuxData();
577 FreeTreeNode(t);
578 }
579 }
580
581 // call the function DeleteTree to deallocate the nodes. then
582 // set the root pointer back to NULL
ClearTree(TreeNode * & t)583 void Tree::ClearTree(TreeNode * &t)
584 {
585 DeleteTree(t);
586 t = NULL; // root now NULL
587 }
588
589 // delete all nodes in list
ClearList(void)590 void Tree::ClearList(void)
591 {
592 delete root;
593 delete current;
594 size = 0;
595 }
596
597 #endif
598