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