// file: $isip/class/dstr/Tree/Tree.h // version: $Id: Tree.h 8932 2002-12-22 20:46:07Z parihar $ // // make sure definitions are made only once // #ifndef ISIP_TREE #define ISIP_TREE // isip include files // #ifndef ISIP_DSTR_BASE #include #endif #ifndef ISIP_SINGLE_LINKED_LIST #include #endif #ifndef ISIP_HASH_TABLE #include #endif #ifndef ISIP_STACK #include #endif #ifndef ISIP_QUEUE #include #endif #ifndef ISIP_HASH_KEY #include #endif #ifndef ISIP_TREE_NODE #include #endif #ifndef ISIP_VECTOR #include #endif #ifndef ISIP_CONSOLE #include #endif // forward class definitions // template class TreeNode; template class TreeDiagnose; // Tree: this class implements a Tree data structure using the left child // right sibling representation. // template class Tree : private DoubleLinkedList< TreeNode > { //--------------------------------------------------------------------------- // // public constants // //--------------------------------------------------------------------------- public: // define the class name // static const String CLASS_NAME; //---------------------------------------- // // i/o related constants // //---------------------------------------- static const String DEF_PARAM; static const String PARAM_ROOT_ITEM; static const String PARAM_ROOT_ADJACENT; static const String PARAM_NODE_ITEMS; static const String PARAM_NODE_ADJACENT; //---------------------------------------- // // default values and arguments // //---------------------------------------- // default values // // default arguments to methods // //---------------------------------------- // // error codes // //---------------------------------------- //--------------------------------------------------------------------------- // // protected data // //--------------------------------------------------------------------------- protected: // the allocation mode // DstrBase::ALLOCATION alloc_d; // define the root of the tree // TreeNode root_d; // debugging parameters // static Integral::DEBUG debug_level_d; // define the memory manager // static MemoryManager mgr_d; //--------------------------------------------------------------------------- // // required public methods // //--------------------------------------------------------------------------- public: // static methods: // the diagnose method is moved outside the class header file and // defined in the TreeDiagnose.h in order to avoid issues // with preprocessing of the diagnose code. // static const String& name(); // method: setDebug // static bool8 setDebug(Integral::DEBUG debug_level) { debug_level_d = debug_level; return true; } // other debug methods // bool8 debug(const unichar* msg) const; // destructor/constructor(s) // ~Tree(); Tree(DstrBase::ALLOCATION alloc = DstrBase::DEF_ALLOCATION); Tree(const Tree& copy_Tree); // assign method // bool8 assign(const Tree& copy_stack); // method: operator= // Tree& operator=(const Tree& arg) { assign(arg); return *this; } // equality method // bool8 eq(const Tree& arg) const; // sofSize method // int32 sofSize() const; // method: read // bool8 read(Sof& sof, int32 tag) { return read(sof, tag, name()); } // method: write // bool8 write(Sof& sof, int32 tag) const { return write(sof, tag, name()); } // other read methods // bool8 read(Sof& sof, int32 tag, const String& name); bool8 readData(Sof& sof, const String& pname = DEF_PARAM, int32 size = SofParser::FULL_OBJECT, bool8 param = true, bool8 nested = false); // other write methods // bool8 write(Sof& sof, int32 tag, const String& name) const; bool8 writeData(Sof& sof, const String& pname = DEF_PARAM) const; // method: new // static void* operator new(size_t size) { return mgr_d.get(); } // method: new[] // static void* operator new[](size_t size) { return mgr_d.getBlock(size); } // method: delete // static void operator delete(void* ptr) { mgr_d.release(ptr); } // method: delete[] // static void operator delete[](void* ptr) { mgr_d.releaseBlock(ptr); } // method: setGrowSize // static bool8 setGrowSize(int32 grow_size) { return mgr_d.setGrow(grow_size); } // clear method // bool8 clear(Integral::CMODE cmode = Integral::DEF_CMODE); //--------------------------------------------------------------------------- // // class-specific public methods: // tree manipulation methods // //--------------------------------------------------------------------------- // method: getRoot // TreeNode* getRoot() const { return (TreeNode*)&root_d; } // method to set the root item // bool8 setRootItem(TObject* obj); // insert methods // TreeNode* insert(TObject* obj); bool8 insertChild(TreeNode* pnode, TreeNode* cnode); // remove methods // bool8 remove(); bool8 remove(TObject*& obj); // item containment methods // bool8 find(const TObject* obj); bool8 find(const TreeNode* node); bool8 contains(const TObject* obj) const; bool8 contains(const TreeNode* node) const; // this method extracts the structure of the tree and places them // in two lists. the first list contains the tree node and the second // list contains its corresponding children // bool8 get(Vector& root_adj, SingleLinkedList& node_obj, SingleLinkedList >& node_adj); // this method uses the extracted structure of the tree in the two // lists as a blue print to reconstruct the tree structure // bool8 set(Vector& root_adj, SingleLinkedList& node_obj, SingleLinkedList >& node_adj); //--------------------------------------------------------------------------- // // class-specific public methods: // tree allocation mode methods // //--------------------------------------------------------------------------- // method: getAllocationMode // DstrBase::ALLOCATION getAllocationMode() const { return alloc_d; } // method: setAllocationMode // bool8 setAllocationMode(DstrBase::ALLOCATION alloc) { alloc_d = alloc; return true; } //--------------------------------------------------------------------------- // // class-specific public methods: // tree traversal methods // //--------------------------------------------------------------------------- // post-order traversal visits the left child first, then the right child, // and finally visits the parent node // bool8 postorderTreeTraversal(SingleLinkedList >& arg); // pre-order traversal visits parent node first, then the left child, // and finally visits the right child // bool8 preorderTreeTraversal(SingleLinkedList >& arg); // in-order traversal visits left child first, then the parent node, // and finally visits the right child // bool8 inorderTreeTraversal(SingleLinkedList >& arg); // level-order traversal visits all nodes at level one (namely the root) // before visiting all nodes at level two and so on... // bool8 levelorderTreeTraversal(SingleLinkedList >& arg); //--------------------------------------------------------------------------- // // class-specific public methods: // double linked list methods // //--------------------------------------------------------------------------- // the Tree class derives the DoubleLinkedList bases class which // is used as the primary underlying container class. to prevent the // user from circumventing the Tree's interface and interacting // directly with the DoubleLinkedList we use private inheritance. // we define here the methods of the DoubleLinkedList interface that // the user is permitted access to. // using DoubleLinkedList< TreeNode >::length; using DoubleLinkedList< TreeNode >::gotoFirst; using DoubleLinkedList< TreeNode >::gotoNext; using DoubleLinkedList< TreeNode >::gotoPrev; using DoubleLinkedList< TreeNode >::getCurr; using DoubleLinkedList< TreeNode >::getFirst; using DoubleLinkedList< TreeNode >::getLast; using DoubleLinkedList< TreeNode >::gotoMark; using DoubleLinkedList< TreeNode >::setMark; using DoubleLinkedList< TreeNode >::gotoPosition; using DoubleLinkedList< TreeNode >::getPosition; using DoubleLinkedList< TreeNode >::isLast; using DoubleLinkedList< TreeNode >::isEmpty; using DoubleLinkedList< TreeNode >::isMarkedElement; //--------------------------------------------------------------------------- // // private methods // //--------------------------------------------------------------------------- private: // tree traversal iterators // bool8 postorderTreeIterator(Stack >& stack); bool8 preorderTreeIterator(Stack >& stack); bool8 inorderTreeIterator(TreeNode* parent, Queue >& queue); bool8 levelorderTreeIterator(SingleLinkedList >& arg, Queue >& queue); // declare friend classes // template friend class TreeDiagnose; }; //----------------------------------------------------------------------------- // // we define non-integral constants at the end of class definition for // templates (for non-templates these are defined in the default constructor) // //----------------------------------------------------------------------------- // constants: required constants such as the class name // template const String Tree::CLASS_NAME(L"Tree"); template const String Tree::DEF_PARAM(L"values"); template const String Tree::PARAM_ROOT_ITEM(L"root_item"); template const String Tree::PARAM_ROOT_ADJACENT(L"root_adjacent"); template const String Tree::PARAM_NODE_ITEMS(L"node_items"); template const String Tree::PARAM_NODE_ADJACENT(L"node_adjacent"); // static instantiations: debug level // template Integral::DEBUG Tree::debug_level_d = Integral::NONE; // static instantiations: the memory manager // template MemoryManager Tree::mgr_d(sizeof(Tree), CLASS_NAME); // below are all the methods for the Tree template class // // --------------------------------------------------------------------- // // required static methods // //---------------------------------------------------------------------- // method: name // // arguments: none // // return: a static String& containing the class name // // this method returns the class name // template const String& Tree::name() { // create the static name string for this class and return it // static String cname(CLASS_NAME); cname.clear(); cname.concat(CLASS_NAME); cname.concat(L"<"); cname.concat(TObject::name()); cname.concat(L">"); // return the name // return cname; } // --------------------------------------------------------------------- // // required debug methods // //---------------------------------------------------------------------- // method: debug // // arguments: // unichar* msg: (input) information message // // return: a bool8 value indicating status // // this method dumps the contents of an object to the console // template bool8 Tree::debug(const unichar* msg_a) const { // dump the root node // root_d.debug(L"root_d"); // dump the remaining nodes // DoubleLinkedList< TreeNode >::debug(L"nodes"); // exit gracefully // return true; } //------------------------------------------------------------------------ // // required destructor/constructor(s) // //----------------------------------------------------------------------- // method: destructor // // arguments: none // // return: none // template Tree::~Tree() { // free memory // clear(); } // method: default constructor // // arguments: // DstrBase::ALLOCATION alloc: (input) the flag to specify whether or not the // item memory is allocated by the node itself // // return: none // template Tree::Tree(DstrBase::ALLOCATION alloc_a) { // set the allocation flag // alloc_d = alloc_a; // set the allocation mode for the underlying container // DoubleLinkedList< TreeNode >::setAllocationMode(DstrBase::USER); } // method: copy constructor // // arguments: // const Tree& copy_tree: (input) the Tree to copy // // return: none // template Tree::Tree(const Tree& copy_tree_a) { // set the allocation mode for the underlying container // DoubleLinkedList< TreeNode >::setAllocationMode(DstrBase::USER); // call the assign method to copy the Tree // assign(copy_tree_a); } //------------------------------------------------------------------------ // // required assign methods // //------------------------------------------------------------------------- // method: assign // // arguments: // const Tree& copy_tree: (input) the Tree to copy // // return: a bool8 value indicating status // // this method copies the contents of the input to this Tree // template bool8 Tree::assign(const Tree& copy_tree_a) { // declare local variables // Vector root_adj; SingleLinkedList node_obj; SingleLinkedList > node_adj; // set the root item // root_d.assign(copy_tree_a.root_d); // get the structure of the input tree // const_cast &>(copy_tree_a).get(root_adj, node_obj, node_adj); // set the structure of the current tree // this->set(root_adj, node_obj, node_adj); // exit gracefully // return true; } //------------------------------------------------------------------------ // // required equality methods // //------------------------------------------------------------------------ // method: eq // // arguments: // const Tree& compare_tree: (input) the Tree to compare // // return: a bool8 value indicating status // // this method compares two Trees for equivalence. two Trees are equivalent // if all corresponding items are equivalent // template bool8 Tree::eq(const Tree& compare_tree_a) const { // declare local variables // Vector root_adj_00; SingleLinkedList node_obj_00; SingleLinkedList > node_adj_00; Vector root_adj_01; SingleLinkedList node_obj_01; SingleLinkedList > node_adj_01; // compare the root item // if (!root_d.eq(compare_tree_a.root_d)) { return false; } // extract the structure of this tree // const_cast *>(this)->get(root_adj_00, node_obj_00, node_adj_00); // extract the structure of the input tree // const_cast &>(compare_tree_a).get(root_adj_01, node_obj_01, node_adj_01); // test the structure for equavalence // if (!root_adj_00.eq(root_adj_01)) { return false; } if (!node_obj_00.eq(node_obj_01)) { return false; } if (!node_adj_00.eq(node_adj_01)) { return false; } // if we have reached this far then they must be equal // return true; } //------------------------------------------------------------------------- // // required memory management methods // //------------------------------------------------------------------------- // method: clear // // arguments: // Integral::CMODE cmode_a: (input) clear mode // // return: a bool8 value indicating status // // this method clears the contents of the list by the setting of cmode_a // template bool8 Tree::clear(Integral::CMODE cmode_a) { // for RETAIN mode, call clear on every object but do not change // topology. for FREE mode we also need to call clear(FREE) on all // TObjects, but we will also delete the topology below. // if ((cmode_a == Integral::RETAIN) || (cmode_a == Integral::FREE)) { for (bool8 more = gotoFirst(); more; more = gotoNext()) { ((TObject*)(getCurr()->getItem()))->clear(cmode_a); } if (root_d.getItem() != (TObject*)NULL) { root_d.getItem()->clear(cmode_a); } } // for RETAIN mode we are done, make no changes to topology // if (cmode_a == Integral::RETAIN) { return true; } // when the graph is in SYSTEM-allocation mode or the clear mode is // free we need to delete the TObject // for (bool8 more = gotoFirst(); more; more = gotoNext()) { if ((alloc_d == SYSTEM) || (cmode_a == Integral::FREE)) { // delete the TObject // delete getCurr()->getItem(); } // set the pointer to null // ((TreeNode*)getCurr())->setItem((TObject*)NULL); } if ((alloc_d == SYSTEM) || (cmode_a == Integral::FREE)) { // delete the TObject // if (root_d.getItem() != (TObject*)NULL) { delete root_d.getItem(); } } // set the pointer to null // root_d.setItem((TObject*)NULL); // clear the tree nodes list // DoubleLinkedList< TreeNode >::setAllocationMode(DstrBase::SYSTEM); DoubleLinkedList< TreeNode >::clear(Integral::RESET); DoubleLinkedList< TreeNode >::setAllocationMode(DstrBase::USER); // exit gracefully // return true; } //------------------------------------------------------------------------ // // class-specific public methods: // i/o methods // //------------------------------------------------------------------------ // method: read // // arguments: // Sof& sof: (input) sof file object // int32 tag: (input) sof object instance tag // const String& name: (input) sof object instance name // // return: a bool8 value indicating status // // this method has the object read itself from an Sof file according // to the specified name and tag // template bool8 Tree::read(Sof& sof_a, int32 tag_a, const String& name_a) { // exit gracefully // return true; } // method: readData // // arguments: // Sof& sof: (input) sof file object // const String& pname: (input) parameter name // int32 size: (input) size in bytes of object (or FULL_OBJECT) // bool8 param: (input) is the parameter name in the file? // bool8 nested: (input) are we nested? // // return: a bool8 value indicating status // // this method has the object read itself from an Sof file. it assumes // that the Sof file is already positioned correctly // template bool8 Tree::readData(Sof& sof_a, const String& pname_a, int32 size_a, bool8 param_a, bool8 nested_a) { // exit gracefully // return true; } // method: sofSize // // arguments: none // // return: size of object // // this method returns the size of the object in the Sof file and is // used for binary write // template int32 Tree::sofSize() const { // return the size // return bytes; } // method: write // // arguments: // Sof& sof: (input) sof file object // int32 tag: (input) sof object instance tag // const String& name: (input) sof object instance name // // return: a bool8 value indicating status // // this method has the object write itself to an Sof file // template bool8 Tree::write(Sof& sof_a, int32 tag_a, const String& name_a) const { // exit gracefully // return true; } //------------------------------------------------------------------------ // // class-specific public methods: // tree manipulation methods // //------------------------------------------------------------------------ // method: setRootItem // // arguments: // TObject* obj: (input) object to be inserted in the tree // // return: a bool8 value indicating status // // this method inserts the input object as the root item // template bool8 Tree::setRootItem(TObject* obj_a) { // perform error checking // if (obj_a == (TObject*)NULL) { Error::handle(name(), L"insert", Error::ARG, __FILE__, __LINE__); return (TreeNode*)NULL; } // declare local variables and allocate a new TreeNode object // TObject* new_obj = (TObject*)NULL; // when the tree is in SYSTEM mode make a copy of the object // if (alloc_d == SYSTEM) { new_obj = new TObject(*obj_a); } // assign the object pointer when in USER mode // else { new_obj = obj_a; } // set the object on the tree node // root_d.setItem(new_obj); // exit gracefully // return true; } // method: insert // // arguments: // TObject* obj: (input) object to be inserted in the tree // // return: a bool8 value indicating status // // this method inserts the input object into the tree structure // template TreeNode* Tree::insert(TObject* obj_a) { // perform error checking // if (obj_a == (TObject*)NULL) { Error::handle(name(), L"insert", Error::ARG, __FILE__, __LINE__); return (TreeNode*)NULL; } // declare local variables and allocate a new TreeNode object // TObject* new_obj = (TObject*)NULL; TreeNode* node = new TreeNode(); // when the tree is in SYSTEM mode make a copy of the object // if (alloc_d == SYSTEM) { new_obj = new TObject(*obj_a); } // assign the object pointer when in USER mode // else { new_obj = obj_a; } // set the object on the tree node // node->setItem(new_obj); // add vertex on the graph // DoubleLinkedList< TreeNode >::insert(node); // exit gracefully // return node; } // method: insertChild // // arguments: // TreeNode* pnone: (input) parent tree node // TreeNode* cnone: (input) child tree node // // return: a bool8 value indicating status // // this method sets the child node as one of the children of the parent node // template bool8 Tree::insertChild(TreeNode* pnode_a, TreeNode* cnode_a) { // declare local variables // TreeNode* node = (TreeNode*)NULL; // verify that the input is valid // if ((pnode_a == (TreeNode*)NULL) || (cnode_a == (TreeNode*)NULL)) { return Error::handle(name(), L"insertChild", Error::ARG, __FILE__, __LINE__); } // child cannot have multiple children // if (cnode_a->getParent() != (TreeNode*)NULL) { return Error::handle(name(), L"insertChild", Error::ARG, __FILE__, __LINE__); } // if the left child is null set the child node as the left child // if (pnode_a->getLeftChild() == (TreeNode*)NULL) { pnode_a->setLeftChild(cnode_a); } // else set the child node as a right sibling // else { // if the right sibling is null set the child node as the right sibling // if ((node = pnode_a->getLeftChild()->getRightSibling()) == (TreeNode*)NULL) { pnode_a->getLeftChild()->setRightSibling(cnode_a); } // insert the child node as one of the right siblings of the left child // else { while (node->getRightSibling() != (TreeNode*)NULL) { node = node->getRightSibling(); } node->setRightSibling(cnode_a); } } // set the parent of the child node // cnode_a->setParent(pnode_a); // increment the degree of the parent node // pnode_a->increment(); // exit gracefully // return true; } // method: remove // // arguments: none // // return: a bool8 value indicating status // // this method removes the current tree node form the tree structure // template bool8 Tree::remove() { // make sure the current tree node is valid // TreeNode* this_node = (TreeNode*)this->getCurr(); if (this_node == (TreeNode*)NULL) { return Error::handle(name(), L"remove", Error::ARG, __FILE__, __LINE__); } // unlink the right siblings that reference this node // TreeNode* pnode = this_node->getParent(); if (pnode != (TreeNode*)NULL) { TreeNode* tnode = pnode->getLeftChild(); while (tnode != (TreeNode*)NULL) { if (tnode->getRightSibling() == this_node) { tnode->setRightSibling(this_node->getRightSibling()); break; } tnode = tnode->getRightSibling(); } } // unlink the children that reference this node // TreeNode* lnode = this_node->getLeftChild(); if (lnode != (TreeNode*)NULL) { lnode->setParent((TreeNode*)NULL); TreeNode* tnode = lnode->getRightSibling(); while(tnode != (TreeNode*)NULL) { tnode->setParent((TreeNode*)NULL); tnode = tnode->getRightSibling(); } } // clear the contents of the tree node // this_node->clear(Integral::FREE); // decrement the degree of the parent node // if (pnode != (TreeNode*)NULL) { pnode->decrement(); } // remove the object from the linked list // bool8 status = false; TreeNode* tree_node; status = DoubleLinkedList< TreeNode >::remove(tree_node); delete tree_node; return status; } // method: remove // // arguments: // TObject*& obj: (input) object to be removed // // return: a bool8 value indicating status // // this method removes the input tree node form the tree structure // template bool8 Tree::remove(TObject*& obj_a) { // make sure the current tree node is valid // TreeNode* this_node = (TreeNode*)this->getCurr(); if (this_node == (TreeNode*)NULL) { return Error::handle(name(), L"remove", Error::ARG, __FILE__, __LINE__); } // make sure memory is allocated if we are SYSTEM-allocated // if ((alloc_d == SYSTEM) && (obj_a == (TObject*)NULL)) { return Error::handle(name(), L"remove", Error::ARG, __FILE__, __LINE__); } // when in SYSTEM mode make a copy of the object data // if (alloc_d == SYSTEM) { obj_a->assign(*this_node->getItem()); delete this_node->getItem(); } // when in USER mode assign the object pointer // else { obj_a = this_node->getItem(); } // unlink the right siblings that reference this node // TreeNode* pnode = this_node->getParent(); if (pnode != (TreeNode*)NULL) { TreeNode* tnode = pnode->getLeftChild(); while (tnode != (TreeNode*)NULL) { if (tnode->getRightSibling() == this_node) { tnode->setRightSibling(this_node->getRightSibling()); break; } tnode = tnode->getRightSibling(); } } // unlink the children that reference this node // TreeNode* lnode = this_node->getLeftChild(); if (lnode != (TreeNode*)NULL) { lnode->setParent((TreeNode*)NULL); TreeNode* tnode = lnode->getRightSibling(); while(tnode != (TreeNode*)NULL) { tnode->setParent((TreeNode*)NULL); tnode = tnode->getRightSibling(); } } // clear the contents of the tree node // this_node->clear(); // decrement the degree of the parent node // if (pnode != (TreeNode*)NULL) { pnode->decrement(); } // remove the object from the linked list // bool8 status = false; TreeNode* tree_node; status = DoubleLinkedList< TreeNode >::remove(tree_node); delete tree_node; return status; } // method: contains // // arguments: // TObject* obj: (input) the object to be found // // return: a bool8 value indicating status // // this method determines if the input object is in the list of vertices // template bool8 Tree::contains(const TObject* obj_a) const { // check if the input object is NULL // if (obj_a == (TObject*)NULL) { return Error::handle(name(), L"contains", Error::ARG, __FILE__, __LINE__); } // save the current position // int32 old_pos = const_cast* >(this)->getPosition(); // temporary variables // bool8 obj_found = false; bool8 more_nodes = const_cast* >(this)->gotoFirst(); // search from the beginning for the item // while (!obj_found && more_nodes) { // get the current node // TreeNode* this_node = (TreeNode*) const_cast* >(this)->getCurr(); // get the object contained in the node // TObject* this_obj = this_node->getItem(); // compare the objects for equality // obj_found = obj_a->eq(*this_obj); if (!obj_found) { more_nodes = const_cast* >(this)->gotoNext(); } } // restore the previous position // const_cast* >(this)->gotoPosition(old_pos); // return whether or not the object was found // return obj_found; } // method: contains // // arguments: // TreeNode* node: (input) the node to be found // // return: a bool8 value indicating status // // this method determines if the input node is in the list of // vertices. note that we can't just call list contains since we only // want to compare pointers, not values. // template bool8 Tree::contains(const TreeNode* node_a) const { // check if the input object is NULL // if (node_a == (TreeNode*)NULL) { return Error::handle(name(), L"contains", Error::NULL_ARG, __FILE__, __LINE__); } // save the current position // int32 old_pos = const_cast* >(this)->getPosition(); // temporary variables // bool8 node_found = false; bool8 more_nodes = const_cast* >(this)->gotoFirst(); // search from the beginning for the item // while (!node_found && more_nodes) { // get the current node // TreeNode* this_node = (TreeNode*) const_cast* >(this)->getCurr(); // compare the pointers for equality // if (this_node == node_a) { node_found = true; } if (!node_found) { more_nodes = const_cast* >(this)->gotoNext(); } } // restore the previous state // const_cast* >(this)->gotoPosition(old_pos); // return whether or not the object was found // return node_found; } // method: find // // arguments: // TObject* obj: (input) the object to be found // // return: a bool8 value indicating status // // this method determines if the input object is in the list of vertices // and moves the list current pointer to the first occurance of the object // template bool8 Tree::find(const TObject* obj_a) { // check if the input object is NULL // if (obj_a == (TObject*)NULL) { return Error::handle(name(), L"find", Error::NULL_ARG, __FILE__, __LINE__); } // save the current position // this->setMark(); // temporary variables // bool8 obj_found = false; bool8 more_nodes = this->gotoFirst(); // search from the beginning for the item // while (!obj_found && more_nodes) { // get the current node // TreeNode* this_node = (TreeNode*)this->getCurr(); // get the object contained in the node // TObject* this_obj = this_node->getItem(); // compare the objects for equality // obj_found = obj_a->eq(*this_obj); if (!obj_found) { more_nodes = this->gotoNext(); } } if (!obj_found) { this->gotoMark(); } // return whether or not the object was found // return obj_found; } // method: find // // arguments: // TreeNode* node: (input) the node to be found // // return: a bool8 value indicating status // // this method determines if the input node is in the list of // vertices. if found the node list is left pointing to the // node. note that we can't just call list contains since we only // want to compare pointers, not values. // template bool8 Tree::find(const TreeNode* node_a) { // check if the input object is NULL // if (node_a == (TreeNode*)NULL) { return Error::handle(name(), L"find", Error::NULL_ARG, __FILE__, __LINE__); } // save the current position // int32 old_pos = const_cast* >(this)->getPosition(); // temporary variables // bool8 node_found = false; bool8 more_nodes = const_cast* >(this)->gotoFirst(); // search from the beginning for the item // while (!node_found && more_nodes) { // get the current node // TreeNode* this_node = (TreeNode*)const_cast* >(this)->getCurr(); // compare the pointers for equality // if (this_node == node_a) { node_found = true; } if (!node_found) { more_nodes = const_cast* >(this)->gotoNext(); } } // restore the previous state if the node was not found // if (!node_found) { const_cast* >(this)->gotoPosition(old_pos); } // return whether or not the object was found // return node_found; } // method: set // // arguments: // Vector& root_adj: (input) adjecent nodes to root node // SingleLinkedList& node_obj: (input) tree node items // SingleLinkedList >& node_adj: (input) adjacent nodes to tree nodes // // return: a bool8 value indicating status // // this method uses the extracted structure of the tree in the two // lists as a blue print to reconstruct the tree structure // template bool8 Tree::set(Vector& root_adj_a, SingleLinkedList& node_obj_a, SingleLinkedList >& node_adj_a) { // declare local variables // Ulong index = 0; Vector* indices = (Vector*)NULL; TreeNode* node = (TreeNode*)NULL; HashTable > khash(DstrBase::USER); SingleLinkedList > nodes(DstrBase::USER); // clear the contents of the tree structure // clear(); // loop over each element in the item list // for (bool8 more = node_obj_a.gotoFirst(); more; more = node_obj_a.gotoNext()) { node = insert(node_obj_a.getCurr()); khash.insert(index, node); nodes.insert(node); index++; } // connect the root node to its adjacent nodes // for (int32 i=0; i < root_adj_a.length(); i++) { insertChild(this->getRoot(), khash.get(root_adj_a(i))); } // connect the remaining tree nodes to its adjacent nodes // nodes.gotoFirst(); for (bool8 more = node_adj_a.gotoFirst(); more; more = node_adj_a.gotoNext()) { indices = node_adj_a.getCurr(); for (int32 i=0; i < indices->length(); i++) { insertChild(nodes.getCurr(), khash.get((*indices)(i))); } nodes.gotoNext(); } // exit gracefully // return true; } // method: get // // arguments: // Vector& root_adj: (output) adjecent nodes to root node // SingleLinkedList& node_obj: (output) tree node items // SingleLinkedList >& node_adj: (output) adjacent nodes to tree nodes // // return: a bool8 value indicating status // // this method extracts the structure of the tree and places them // in two lists. the first list contains the tree node and the second // list contains its corresponding children // template bool8 Tree::get(Vector& root_adj_a, SingleLinkedList& node_obj_a, SingleLinkedList >& node_adj_a) { // declare local variables // Ulong index = 0; Vector indices; HashKey > hashkey; HashTable >, Ulong> khash; TreeNode* this_node = (TreeNode*)NULL; // save the current state of the list // this->setMark(); // make sure that the list of node object are in USER mode // node_obj_a.setAllocationMode(DstrBase::USER); // add the tree node items to the list // for (bool8 more = this->gotoFirst(); more; more = this->gotoNext()) { // add the tree node to the list // node_obj_a.insert(this->getCurr()->getItem()); // associate a unique number with the tree node // hashkey.assign(this->getCurr()); khash.insert(hashkey, &index); // increment the index // index++; } // add the nodes adjacent to the root to the list // this_node = this->getRoot(); if (this_node == (TreeNode*)NULL) { return Error::handle(name(), L"get", Error::ARG, __FILE__, __LINE__); } // get the degree of the root node // int32 degree = this_node->degree(); if (degree > 0) { // set the length of the vector to the degree of the node // root_adj_a.setLength(degree); // add the position of the left child to the vector // int32 pos = 0; TreeNode* lnode = this_node->getLeftChild(); if (lnode != (TreeNode*)NULL) { hashkey.assign(lnode); root_adj_a(pos++) = *(khash.get(hashkey)); // add the positions of the right siblings to the vector // TreeNode* rnode = lnode->getRightSibling(); while (rnode != (TreeNode*)NULL) { hashkey.assign(rnode); root_adj_a(pos++) = *(khash.get(hashkey)); rnode = rnode->getRightSibling(); } } } // add the nodes adjacent to the nodes in the tree to the list // for (bool8 more = this->gotoFirst(); more; more = this->gotoNext()) { // get the current tree node // this_node = this->getCurr(); if (this_node == (TreeNode*)NULL) { return Error::handle(name(), L"get", Error::ARG, __FILE__, __LINE__); } // clear the previous list of indices // indices.clear(); // get the degree of the current tree node // int32 degree = this_node->degree(); if (degree > 0) { // set the length of the vector to the degree of the node // indices.setLength(degree); // add the position of the left child to the vector // int32 pos = 0; TreeNode* lnode = this_node->getLeftChild(); if (lnode != (TreeNode*)NULL) { hashkey.assign(lnode); indices(pos++) = *(khash.get(hashkey)); // add the positions of the right siblings to the vector // TreeNode* rnode = lnode->getRightSibling(); while (rnode != (TreeNode*)NULL) { hashkey.assign(rnode); indices(pos++) = *(khash.get(hashkey)); rnode = rnode->getRightSibling(); } } } // add the vector of indices to the list // node_adj_a.insert(&indices); } // restore the original state of the list // this->gotoMark(); // exit gracefully // return true; } //------------------------------------------------------------------------ // // class-specific public methods: // tree traversal methods // //------------------------------------------------------------------------ // method: postorderTreeTraversal // // arguments: // SingleLinkedList >& arg: (output) traversed nodes in the tree // // return: a bool8 value indicating status // // post-order traversal visits the left child first, then the right child, // and finally visits the parent node // template bool8 Tree::postorderTreeTraversal(SingleLinkedList >& arg_a) { // declare local variables // Stack > stack(DstrBase::USER); // get the root of the tree // TreeNode* current = this->getRoot(); if (current == (TreeNode*)NULL) { return Error::handle(name(), L"postorderTreeTraversal", Error::ARG, __FILE__, __LINE__); } // push the root on the stack // stack.push(current); // recursively descend down the tree and visit the children in order // postorderTreeIterator(stack); // insert elements of the stack into the list // while(!stack.isEmpty()) { arg_a.insert(stack.pop()); } // exit gracefully // return true; } // method: postorderTreeIterator // // arguments: // Stack >& stack: (input) input stack // // return: a bool8 value indicating status // // post-order traversal iterator method // template bool8 Tree::postorderTreeIterator(Stack >& stack_a) { // verify inputs // if (stack_a.isEmpty()) { return Error::handle(name(), L"postorderTreeIterator", Error::ARG, __FILE__, __LINE__); } // get the item on the top of the stack // TreeNode* current = stack_a.peek(); if (current == (TreeNode*)NULL) { return Error::handle(name(), L"postorderTreeIterator", Error::ARG, __FILE__, __LINE__); } // get the children associated with the current tree node // DoubleLinkedList > list(DstrBase::USER); TreeNode* child = current->getLeftChild(); if (child != (TreeNode*)NULL) { list.insert(child); child = child->getRightSibling(); while(child != (TreeNode*)NULL) { list.insert(child); child = child->getRightSibling(); } } // recursively descend down the tree and visit the children in order // for (bool8 more = list.gotoLast(); more; more = list.gotoPrev()) { stack_a.push(list.getCurr()); postorderTreeIterator(stack_a); } // exit gracefully // return true; } // method: preorderTreeTraversal // // arguments: // SingleLinkedList >& arg: (output) traversed nodes in the tree // // return: a bool8 value indicating status // // pre-order traversal visits parent node first, then the left child, // and finally visits the right child // template bool8 Tree::preorderTreeTraversal(SingleLinkedList >& arg_a) { // declare local variables // Stack > stack(DstrBase::USER); // get the root of the tree // TreeNode* current = this->getRoot(); if (current == (TreeNode*)NULL) { return Error::handle(name(), L"postorderTreeTraversal", Error::ARG, __FILE__, __LINE__); } // push the root on the stack // stack.push(current); // recursively descend down the tree and visit the children in order // preorderTreeIterator(stack); // insert elements of the stack into the list // while(!stack.isEmpty()) { arg_a.insert(stack.pop()); } arg_a.reverse(); // exit gracefully // return true; } // method: preorderTreeIterator // // arguments: // Stack >& stack: (input) input stack // // return: a bool8 value indicating status // // post-order traversal iterator method // template bool8 Tree::preorderTreeIterator(Stack >& stack_a) { // verify inputs // if (stack_a.isEmpty()) { return Error::handle(name(), L"preorderTreeIterator", Error::ARG, __FILE__, __LINE__); } // get the item at the fornt of the stack // TreeNode* current = stack_a.peek(); if (current == (TreeNode*)NULL) { return Error::handle(name(), L"preorderTreeIterator", Error::ARG, __FILE__, __LINE__); } // get the children associated with the current tree node // DoubleLinkedList > list(DstrBase::USER); TreeNode* child = current->getLeftChild(); if (child != (TreeNode*)NULL) { list.insert(child); child = child->getRightSibling(); while(child != (TreeNode*)NULL) { list.insert(child); child = child->getRightSibling(); } } // recursively descend down the tree and visit the children in order // for (bool8 more = list.gotoFirst(); more; more = list.gotoNext()) { stack_a.push(list.getCurr()); preorderTreeIterator(stack_a); } // exit gracefully // return true; } // method: inorderTreeIterator // // arguments: // TreeNode* parent: (input) parent tree node // Queue >& queue: (input) input queue // // return: a bool8 value indicating status // // post-order traversal iterator method // template bool8 Tree::inorderTreeIterator(TreeNode* parent_a, Queue >& queue_a) { // verify the inputs // if (parent_a == (TreeNode*)NULL) { return Error::handle(name(), L"inorderTreeIterator", Error::ARG, __FILE__, __LINE__); } // visit the left child // TreeNode* child = parent_a->getLeftChild(); if (child != (TreeNode*)NULL) { inorderTreeIterator(child, queue_a); } // add the parent to the queue // queue_a.add(parent_a); // visit the right children // if (child != (TreeNode*)NULL) { child = child->getRightSibling(); while (child != (TreeNode*)NULL) { inorderTreeIterator(child, queue_a); child = child->getRightSibling(); } } // exit gracefully // return true; } // method: inorderTreeTraversal // // arguments: // SingleLinkedList >& arg: (output) traversed nodes in the tree // // return: a bool8 value indicating status // // in-order traversal visits left child first, then the parent node, // and finally visits the right child // template bool8 Tree::inorderTreeTraversal(SingleLinkedList >& arg_a) { // declare local variables // Queue > queue(DstrBase::USER); // get the root of the tree // TreeNode* current = this->getRoot(); if (current == (TreeNode*)NULL) { return Error::handle(name(), L"postorderTreeTraversal", Error::ARG, __FILE__, __LINE__); } // recursively descend down the tree and visit the children in order // inorderTreeIterator(current, queue); // insert elements of the queue into the list // while(!queue.isEmpty()) { arg_a.insert(queue.remove()); } // exit gracefully // return true; } // method: levelorderTreeTraversal // // arguments: // SingleLinkedList >& arg: (output) traversed nodes in the tree // // return: a bool8 value indicating status // // level-order traversal visits all nodes at level one (namely the root) // before visiting all nodes at level two and so on... // template bool8 Tree::levelorderTreeTraversal(SingleLinkedList >& arg_a) { // declare local variables // Queue > queue(DstrBase::USER); // get the root of the tree // TreeNode* current = this->getRoot(); if (current == (TreeNode*)NULL) { return Error::handle(name(), L"postorderTreeTraversal", Error::ARG, __FILE__, __LINE__); } // insert the root node in the queue // queue.add(current); // call the iterator as int32 as the queue is not empty // while (!queue.isEmpty()) { levelorderTreeIterator(arg_a, queue); } // exit gracefully // return true; } // method: levelorderTreeIterator // // arguments: // SingleLinkedList >& arg: (output) traversed nodes in the tree // Queue >& queue: (input) input queue // // return: a bool8 value indicating status // // post-order traversal iterator method // template bool8 Tree::levelorderTreeIterator(SingleLinkedList >& arg_a, Queue >& queue_a) { // verify inputs // if (queue_a.isEmpty()) { return Error::handle(name(), L"levelorderTreeIterator", Error::ARG, __FILE__, __LINE__); } // get the parent // TreeNode* parent = queue_a.remove(); if (parent == (TreeNode*)NULL) { return Error::handle(name(), L"levelorderTreeIterator", Error::ARG, __FILE__, __LINE__); } // visit the children // TreeNode* child = parent->getLeftChild(); if (child != (TreeNode*)NULL) { queue_a.add(child); } if (child != (TreeNode*)NULL) { child = child->getRightSibling(); while (child != (TreeNode*)NULL) { queue_a.add(child); child = child->getRightSibling(); } } // insert the parent in the list // arg_a.insert(parent); // exit gracefully // return true; } // end of include file // #endif