1 /* 2 HMat-OSS (HMatrix library, open source software) 3 4 Copyright (C) 2014-2015 Airbus Group SAS 5 6 This program is free software; you can redistribute it and/or 7 modify it under the terms of the GNU General Public License 8 as published by the Free Software Foundation; either version 2 9 of the License, or (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 20 http://github.com/jeromerobert/hmat-oss 21 */ 22 23 /*! \file 24 \ingroup HMatrix 25 \brief Templated Tree class used by ClusterTree and HMatrix. 26 */ 27 #ifndef _TREE_HPP 28 #define _TREE_HPP 29 #include <vector> 30 #include <list> 31 #include <cstddef> 32 #include <assert.h> 33 34 namespace hmat { 35 36 // Forward declaration 37 template <typename TreeNode> class Tree; 38 39 /* Visitor pattern 40 */ 41 enum Visit { tree_preorder, tree_postorder, tree_inorder, tree_leaf }; 42 43 /** Class to recursively apply a given function to all nodes of a tree 44 */ 45 template <typename TreeNode> 46 class TreeProcedure { 47 48 public: TreeProcedure()49 TreeProcedure() {} 50 virtual void visit(TreeNode* node, const Visit order) const = 0; ~TreeProcedure()51 virtual ~TreeProcedure() {} 52 }; 53 54 template <typename TreeNode> 55 class LeafProcedure { 56 57 public: LeafProcedure()58 LeafProcedure() {} 59 virtual void apply(TreeNode* leaf) const = 0; ~LeafProcedure()60 virtual ~LeafProcedure() {} 61 }; 62 63 /*! \brief Templated tree class. 64 65 This class represents a tree of arity N, holding an instance of NodeData in 66 its nodes. 67 */ 68 template <typename TreeNode> 69 class Tree { 70 public: 71 /// depth of the current node in the tree 72 int depth; 73 74 protected: 75 /// empty for a leaf, pointer on a vector of sons otherwise. 76 std::vector<TreeNode*> children; 77 public: 78 /// Pointer to the father, NULL if this node is the root 79 TreeNode* father; 80 81 public: Tree(TreeNode * _father,int _depth=0)82 Tree(TreeNode* _father, int _depth = 0) 83 : depth(_depth), children(), father(_father) {} ~Tree()84 virtual ~Tree() { 85 for (int i=0 ; i<nrChild() ; i++) 86 if (children[i]) 87 delete children[i]; 88 children.clear(); 89 } 90 91 // https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern 92 // "me()->" replaces "this->" when calling a method of TreeNode me()93 TreeNode* me() { 94 return static_cast<TreeNode*>(this); 95 } me() const96 const TreeNode* me() const { 97 return static_cast<const TreeNode*>(this); 98 } 99 100 /*! \brief Insert a child in the children vector. 101 102 If a child is already present, it is removed but not deleted. 103 104 \param index index in the children vector 105 \param child pointeur to the child 106 */ insertChild(int index,TreeNode * child)107 void insertChild(int index, TreeNode *child) { 108 if (nrChild()<=index) 109 children.resize(index+1, (TreeNode*)NULL); 110 children[index] = child; 111 if (child) { 112 child->father = me(); 113 child->depth = depth + 1; 114 } 115 } 116 117 /*! \brief Remove a child, and delete it if necessary. 118 */ removeChild(int index)119 void removeChild(int index) { 120 assert(index>=0 && index<nrChild()); 121 if (children[index]) 122 delete children[index]; 123 children[index] = (TreeNode*)NULL; 124 } 125 126 /** Remove all children without freeing them */ detachChildren()127 void detachChildren() { 128 children.clear(); 129 } 130 131 /*! \brief Return the number of nodes in the tree. 132 */ nodesCount() const133 int nodesCount() const { 134 int result = 1; 135 for (int i=0 ; i<nrChild() ; i++) 136 if (children[i]) 137 result += children[i]->nodesCount(); 138 return result; 139 } 140 141 /*! \brief Return the child of index, or NULL. 142 */ getChild(int index) const143 inline TreeNode *getChild(int index) const { 144 assert(index>=0 && index<nrChild()); 145 return children[index]; 146 } getChild(int index)147 inline TreeNode *&getChild(int index) { 148 assert(index>=0 && index<nrChild()); 149 return children[index]; 150 } 151 getFather() const152 inline TreeNode *getFather() const { 153 return father; 154 } 155 nrChild() const156 inline int nrChild() const { 157 return (int)children.size(); 158 } 159 160 /*! \brief Return true if the node is a leaf (= it has no children). 161 */ isLeaf() const162 inline bool isLeaf() const { 163 return children.empty(); 164 } 165 166 /*! \brief Return a list of nodes. 167 168 Not used anywhere. 169 */ listNodes() const170 virtual std::list<const TreeNode*> listNodes() const { 171 std::list<const TreeNode*> result; 172 result.push_back(me()); 173 for (int i=0 ; i<nrChild() ; i++) 174 if (children[i]) { 175 std::list<const TreeNode*> childNodes = children[i]->listNodes(); 176 result.splice(result.end(), childNodes, childNodes.begin(), childNodes.end()); 177 } 178 return result; 179 } 180 walk(const TreeProcedure<TreeNode> * proc)181 void walk(const TreeProcedure<TreeNode> *proc) { 182 if (isLeaf()) { 183 proc->visit(me(), tree_leaf); // treatment on the leaves 184 } else { 185 proc->visit(me(), tree_preorder); // treatment on a non-leaf before recursion 186 bool first = true; 187 for (int i=0 ; i<nrChild() ; i++) 188 if (children[i]) { 189 if (!first) 190 proc->visit(me(), tree_inorder); // treatment on a non-leaf after 1st child (mainly usefull with 2 children) 191 first = false; 192 children[i]->walk(proc); 193 } 194 proc->visit(me(), tree_postorder); // treatment on a non-leaf after recursion 195 } 196 } 197 apply_on_leaf(const LeafProcedure<TreeNode> & proc)198 void apply_on_leaf(const LeafProcedure<TreeNode>& proc) { 199 if (isLeaf()) { 200 proc.apply(me()); 201 } else { 202 for (int i=0 ; i<nrChild() ; i++) { 203 if (children[i]) { 204 children[i]->apply_on_leaf(proc); 205 } 206 } 207 } 208 } 209 210 }; 211 212 } // end namespace hmat 213 214 #endif // _TREE_HPP 215