#ifndef MTREE_H #define MTREE_H /////////////////////////////////////////////////////////////////////////// // MTree.h - M-ary tree class to hold an XmlDocument // // ver 2.2 // // Language: Visual C++, 2008 // // Platform: Dell Precision T7400, Win7 Professional // // Application: CSE687 - Demo for Project #1, Spring 2010 // // Author: Jim Fawcett, Syracuse University, CST 4-187, // // (315) 443-3948, jfawcett@twcny.rr.com // /////////////////////////////////////////////////////////////////////////// /* * Module Operations: * ================== * Provides an MTree class that holds a finite number of MNodes and * and supports visitation of each node, using depth first search. * * Required Files: * =============== * MTree.h, MTree.cpp, MNodes.h, MNode.cpp * * Build Process: * ============== * cl /D:TEST_MTREE MTree.cpp MNode.cpp * * Maintenance History: * ==================== * ver 2.2 : 02 Mar 10 * - fixed memory leak in MTree::finder(...) * ver 2.1 : 27 Feb 10 * - converted all test stub testing to use MNode. * - added public definitions for copy construction and assignment. * - fixed bug in searching by changing return type of walk to bool * and returning as soon as a find happens. * ver 2.0 : 30 Jan 10 * - removed vector scaffolding, now create test nodes on heap * ver 1.1 : 27 Jan 10 * - added private declarations for copy and assignment * to prevent compiler from generating incorrect versions * ver 1.0 : 23 Jan 09 * - first release */ #include #include #include namespace TMTree { ///////////////////////////////////////////////////////////////////////// // Operation class template class Operation { public: Operation() : level_(0), verbose_(false) {} virtual ~Operation() {} size_t& level() { return level_; } bool& verbose() { return verbose_; } virtual void end(Node* pNode) {} virtual bool operator()(Node* pNode) { std::cout << "\n " << pNode->value(); return false; // don't stop walk } protected: size_t level_; bool verbose_; }; ///////////////////////////////////////////////////////////////////////// // MTree class template class MTree { public: MTree(Operation* pOper=new Operation()); MTree(const MTree& tree); ~MTree(); MTree& operator=(const MTree& tree); Operation* setOperation(Operation* pOper); void makeRoot(Node* pNode); bool walk(Node* pStart); bool walk(); // these two finders do the same thing in different ways Node* find(const std::string& value, Node* pNode = 0); Node* finder(const std::string& value, Node* pNode = 0); void clear(); bool& verbose(); bool isEmpty(); private: //void delete_walk(Node* pNode); Node* pRoot; Node* pFound; Operation* pOper_; bool verbose_; }; //----< constructor accepts operation to apply to each node >------------ template MTree::MTree(Operation* pOper) : pOper_(pOper), pRoot(0), verbose_(false) {} //----< copy constructor depends on virtual MNode::clone() >----------- template MTree::MTree(const MTree &tree) { pRoot = tree.pRoot->clone(); pOper_ = tree.pOper_; } //----< destructor >----------------------------------------------------- template MTree::~MTree() { if(verbose()) std::cout << "\n Deleting tree nodes:"; if(pRoot) delete pRoot; //delete_walk(pRoot); } //----< assignment >----------------------------------------------------- template MTree& MTree::operator =(const MTree& tree) { if(this == &tree) return *this; delete pRoot; pRoot = tree.pRoot->clone(); pOper_ = tree.pOper_; return *this; } //----< remove all nodes >----------------------------------------------- template void MTree::clear() { delete pRoot; } //----< set verbose true or false >---------------------------------------- template bool& MTree::verbose() { return verbose_; } //----< give tree a node to serve as root of tree >------------------------ template void MTree::makeRoot(Node* pMNode) { pRoot = pMNode; } //----< give tree an operation to apply to each node during traversal >---- template Operation* MTree::setOperation(Operation* pOper) { Operation* temp = pOper_; pOper_ = pOper; return temp; // return old operation so can restore later } //----< depth first search based traversal >------------------------------- template bool MTree::walk() { pOper_->verbose() = verbose_; pOper_->level() = 0; if((*pOper_)(pRoot)) return false; // found something so stop walk pRoot->clearMarks(); Node* pTemp; while(pTemp = pRoot->nextUnmarkedChild()) { if(!walk(pTemp)) return false; //if((*pOper_)(pTemp)) return; pOper_->end(pTemp); --(pOper_->level()); } return true; } //----< traversal starting at specific node >------------------------------ template bool MTree::walk(Node* pStart) { pOper_->verbose() = verbose_; ++(pOper_->level()); if((*pOper_)(pStart)) return false; // found something so stop walk pStart->clearMarks(); Node* pTemp; while(pTemp = pStart->nextUnmarkedChild()) { if(!walk(pTemp)) return false; pOper_->end(pTemp); --(pOper_->level()); } return true; } //----< Operation supports finding node with given value >--------------- template class finderOp : public Operation { public: finderOp(const std::string& val, Node* pNode=0) : value_(val), pNode_(pNode), stop(false), verbose_(false) {} bool operator()(Node* pNode) { if(stop) return true; if(verbose()) std::cout << "\n -- value = " << pNode->value(); if(pNode->value() == value_) { pNode_ = pNode; return (stop = true); } return false; } Node* getResult() { return pNode_; } bool& verbose() { return verbose_; } private: Node* pNode_; std::string value_; bool stop; bool verbose_; }; //----< find node with specified value using Operation >------------------- template Node* MTree::finder(const std::string& value, Node* pNode=0) { finderOp* op = new finderOp(value); op->verbose() = verbose(); Operation* oldOp = setOperation(op); walk(); setOperation(oldOp); Node* pFoundNode = op->getResult(); delete op; return pFoundNode; } //----< find node with specified value >----------------------------------- template Node* MTree::find(const std::string& tvalue, Node* pNode) { if(pNode == 0) { pNode = pRoot; pFound = 0; } else if(pFound) return pFound; if(verbose()) std::cout << "\n -- value = " << pNode->value(); if(tvalue == pNode->value()) return pFound = pNode; pNode->clearMarks(); MNode* pTemp; while(pTemp = pNode->nextUnmarkedChild()) { pFound = find(tvalue, pTemp); } return pFound; } //----< is the tree empty? >----------------------------------------------- template bool MTree::isEmpty() { return pRoot == 0; } //----< delete tree nodes on the way back from DFS traversal >------------- //template //void MTree::delete_walk(Node* pStart) //{ // pStart->clearMarks(); // MNode* pTemp; // while(pTemp = pStart->nextUnmarkedChild()) // { // delete_walk(pTemp); // // uncomment to see deletions // // std::cout << "\n " << pTemp->value(); // delete pTemp; // } //} } #endif