第五十五课 树中节点的清除操作
Posted wanmeishenghuo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第五十五课 树中节点的清除操作相关的知识,希望对你有一定的参考价值。
如果一个节点没有子树,那就直接清除这个节点,这就是出口。
添加free函数:
1 #ifndef GTREE_H 2 #define GTREE_H 3 4 #include "Tree.h" 5 #include "GTreeNode.h" 6 #include "Exception.h" 7 8 namespace DTLib 9 { 10 11 template < typename T > 12 class GTree : public Tree<T> 13 { 14 protected: 15 GTreeNode<T>* find(GTreeNode<T>* node, const T& value) const 16 { 17 GTreeNode<T>* ret = NULL; 18 19 if( node != NULL ) 20 { 21 if( node->value == value ) 22 { 23 return node; 24 } 25 else 26 { 27 for(node->child.move(0); !node->child.end() && (ret == NULL); node->child.next()) 28 { 29 ret = find(node->child.current(), value); 30 } 31 } 32 } 33 34 return ret; 35 } 36 37 GTreeNode<T>* find(GTreeNode<T>* node, GTreeNode<T>* obj) const 38 { 39 GTreeNode<T>* ret = NULL; 40 41 if( node == obj ) 42 { 43 return node; 44 } 45 else 46 { 47 if( node != NULL ) 48 { 49 for( node->child.move(0); !node->child.end() && (ret == NULL); node->child.next()) 50 { 51 ret = find(node->child.current(), obj); 52 } 53 } 54 } 55 56 return ret; 57 } 58 59 void free(GTreeNode<T>* node) 60 { 61 if( node != NULL ) 62 { 63 for(node->child.move(0); !node->child.end(); node->child.next()) 64 { 65 free(node->child.current()); 66 } 67 68 delete node; 69 } 70 } 71 public: 72 bool insert(TreeNode<T>* node) 73 { 74 bool ret = true; 75 76 if( node != NULL ) 77 { 78 if( this->m_root == NULL ) //如果待插入节点的父节点为空,则这个节点将为根节点 79 { 80 node->parent = NULL; 81 this->m_root = node; 82 } 83 else 84 { 85 GTreeNode<T>* np = find(node->parent); 86 87 if( np != NULL ) 88 { 89 GTreeNode<T>* n = dynamic_cast<GTreeNode<T>*>(node); 90 91 if( np->child.find(n) < 0 ) 92 { 93 np->child.insert(n); 94 } 95 } 96 else 97 { 98 THROW_EXCEPTION(InvalidParameterException, "Invalid parent tree node..."); 99 } 100 } 101 } 102 else 103 { 104 THROW_EXCEPTION(InvalidParameterException, "Parameter node cannot be NULL ..."); 105 } 106 107 return ret; 108 } 109 110 bool insert(const T& value, TreeNode<T>* parent) 111 { 112 bool ret = true; 113 114 GTreeNode<T>* node = new GTreeNode<T>(); 115 116 if( node != NULL ) 117 { 118 node->value = value; 119 node->parent = parent; 120 121 insert(node); 122 } 123 else 124 { 125 THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); 126 } 127 128 return ret; 129 } 130 131 //删除的节点的子节点我们还需要处理,因此要返回删除节点的指针,这样有机会对里面的元素做进一步操作 132 SharedPointer< Tree<T> > remove(const T& value) 133 { 134 return NULL; 135 } 136 137 SharedPointer< Tree<T> > remove(TreeNode<T>* node) 138 { 139 return NULL; 140 } 141 142 GTreeNode<T>* find(const T& value) const // 返回GTreeNode,赋值兼容性 143 { 144 return find(root(), value); 145 } 146 147 GTreeNode<T>* find(TreeNode<T>* node) const 148 { 149 return find(root(), dynamic_cast<GTreeNode<T>*>(node)); 150 } 151 152 GTreeNode<T>* root() const 153 { 154 return dynamic_cast<GTreeNode<T>*>(this->m_root); 155 } 156 157 int degree() const 158 { 159 return 0; 160 } 161 int count() const 162 { 163 return 0; 164 } 165 166 int height() const 167 { 168 return 0; 169 } 170 171 void clear() 172 { 173 free(root()); 174 175 this->m_root = NULL; 176 } 177 178 ~GTree() 179 { 180 clear(); 181 } 182 }; 183 184 } 185 186 #endif // GTREE_H
测试程序如下:
1 #include <iostream> 2 #include "GTree.h" 3 #include "GTreeNode.h" 4 5 6 using namespace std; 7 using namespace DTLib; 8 9 10 int main() 11 { 12 GTree<char> t; 13 GTreeNode<char>* node = NULL; 14 GTreeNode<char> root; 15 16 root.value = ‘A‘; 17 root.parent = NULL; 18 19 t.insert(&root); 20 21 node = t.find(‘A‘); 22 t.insert(‘B‘, node); 23 t.insert(‘C‘, node); 24 t.insert(‘D‘, node); 25 26 node = t.find(‘B‘); 27 t.insert(‘E‘, node); 28 t.insert(‘F‘, node); 29 30 node = t.find(‘E‘); 31 t.insert(‘K‘, node); 32 t.insert(‘L‘, node); 33 34 node = t.find(‘C‘); 35 t.insert(‘G‘, node); 36 37 node = t.find(‘D‘); 38 t.insert(‘H‘, node); 39 t.insert(‘I‘, node); 40 t.insert(‘J‘, node); 41 42 node = t.find(‘H‘); 43 t.insert(‘M‘, node); 44 45 t.clear(); 46 47 //用链表来验证我们的插入操作,从下至上遍历 48 49 char* s = "KLFGMIJ"; 50 51 for( int i = 0; i < 7; i++ ) 52 { 53 TreeNode<char>* node = t.find(s[i]); 54 55 while( node != NULL ) 56 { 57 cout << node->value << " "; 58 59 node = node->parent; 60 } 61 cout << endl; 62 } 63 64 65 return 0; 66 }
现在我们插入的根节点是在栈上,而在释放时却用了delete。
我们的程序比较小,delete栈中的对象暂时没有体现出bug,但是大型程序这样做是不允许的。
改进GTreeNode.h文件如下:
1 #ifndef GTREENODE_H 2 #define GTREENODE_H 3 4 #include "TreeNode.h" 5 #include "LinkList.h" 6 7 namespace DTLib 8 { 9 10 template < typename T > 11 class GTreeNode : public TreeNode<T> 12 { 13 protected: 14 bool m_flag; 15 16 void* operator new(unsigned int size) throw() 17 { 18 return Object::operator new(size); 19 } 20 public: 21 LinkList<GTreeNode<T>*> child; 22 23 GTreeNode() 24 { 25 m_flag = false; 26 } 27 28 bool flag() 29 { 30 return m_flag; 31 } 32 33 static GTreeNode<T>* NewNode() 34 { 35 GTreeNode<T>* ret = new GTreeNode<T>(); 36 37 if( ret != NULL ) 38 { 39 ret->m_flag = true; 40 } 41 42 return ret; 43 } 44 }; 45 46 } 47 48 #endif // GTREENODE_H
GTree.h改进如下:
1 #ifndef GTREE_H 2 #define GTREE_H 3 4 #include "Tree.h" 5 #include "GTreeNode.h" 6 #include "Exception.h" 7 8 namespace DTLib 9 { 10 11 template < typename T > 12 class GTree : public Tree<T> 13 { 14 protected: 15 GTreeNode<T>* find(GTreeNode<T>* node, const T& value) const 16 { 17 GTreeNode<T>* ret = NULL; 18 19 if( node != NULL ) 20 { 21 if( node->value == value ) 22 { 23 return node; 24 } 25 else 26 { 27 for(node->child.move(0); !node->child.end() && (ret == NULL); node->child.next()) 28 { 29 ret = find(node->child.current(), value); 30 } 31 } 32 } 33 34 return ret; 35 } 36 37 GTreeNode<T>* find(GTreeNode<T>* node, GTreeNode<T>* obj) const 38 { 39 GTreeNode<T>* ret = NULL; 40 41 if( node == obj ) 42 { 43 return node; 44 } 45 else 46 { 47 if( node != NULL ) 48 { 49 for( node->child.move(0); !node->child.end() && (ret == NULL); node->child.next()) 50 { 51 ret = find(node->child.current(), obj); 52 } 53 } 54 } 55 56 return ret; 57 } 58 59 void free(GTreeNode<T>* node) 60 { 61 if( node != NULL ) 62 { 63 for(node->child.move(0); !node->child.end(); node->child.next()) 64 { 65 free(node->child.current()); 66 } 67 68 if( node->flag() ) 69 { 70 delete node; 71 } 72 } 73 } 74 public: 75 bool insert(TreeNode<T>* node) 76 { 77 bool ret = true; 78 79 if( node != NULL ) 80 { 81 if( this->m_root == NULL ) //如果待插入节点的父节点为空,则这个节点将为根节点 82 { 83 node->parent = NULL; 84 this->m_root = node; 85 } 86 else 87 { 88 GTreeNode<T>* np = find(node->parent); 89 90 if( np != NULL ) 91 { 92 GTreeNode<T>* n = dynamic_cast<GTreeNode<T>*>(node); 93 94 if( np->child.find(n) < 0 ) 95 { 96 np->child.insert(n); 97 } 98 } 99 else 100 { 101 THROW_EXCEPTION(InvalidParameterException, "Invalid parent tree node..."); 102 } 103 } 104 } 105 else 106 { 107 THROW_EXCEPTION(InvalidParameterException, "Parameter node cannot be NULL ..."); 108 } 109 110 return ret; 111 } 112 113 bool insert(const T& value, TreeNode<T>* parent) 114 { 115 bool ret = true; 116 117 GTreeNode<T>* node = GTreeNode<T>::NewNode(); 118 119 if( node != NULL ) 120 { 121 node->value = value; 122 node->parent = parent; 123 124 insert(node); 125 } 126 else 127 { 128 THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); 129 } 130 131 return ret; 132 } 133 134 //删除的节点的子节点我们还需要处理,因此要返回删除节点的指针,这样有机会对里面的元素做进一步操作 135 SharedPointer< Tree<T> > remove(const T& value) 136 { 137 return NULL; 138 } 139 140 SharedPointer< Tree<T> > remove(TreeNode<T>* node) 141 { 142 return NULL; 143 } 144 145 GTreeNode<T>* find(const T& value) const // 返回GTreeNode,赋值兼容性 146 { 147 return find(root(), value); 148 } 149 150 GTreeNode<T>* find(TreeNode<T>* node) const 151 { 152 return find(root(), dynamic_cast<GTreeNode<T>*>(node)); 153 } 154 155 GTreeNode<T>* root() const 156 { 157 return dynamic_cast<GTreeNode<T>*>(this->m_root); 158 } 159 160 int degree() const 161 { 162 return 0; 163 } 164 int count() const 165 { 166 return 0; 167 } 168 169 int height() const 170 { 171 return 0; 172 } 173 174 void clear() 175 { 176 free(root()); 177 178 this->m_root = NULL; 179 } 180 181 ~GTree() 182 { 183 clear(); 184 } 185 }; 186 187 } 188 189 #endif // GTREE_H
小结:
以上是关于第五十五课 树中节点的清除操作的主要内容,如果未能解决你的问题,请参考以下文章