第五十六课 树中结点的删除操作
Posted wanmeishenghuo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第五十六课 树中结点的删除操作相关的知识,希望对你有一定的参考价值。
返回的指针谁来负责释放呢?我们采取的措施是使用智能指针来管理这棵树的生命周期。
返回一棵子树的好处是在某些场合,我们能够将H、I、J、M重组,并将它们重新的加回原来的树中。
示例:
main函数使用了p指针指向的内存,但是不负责释放,因为从main函数的角度来看,这片内存不是main函数申请的,而从func函数的角度来看,这片内存是申请给main函数用的,func返回之后就无法控制这片内存了。而C++本身又没有内存释放机制。因此,这片内存处于三不管地带,我们要用智能指针来管理。
于是改造成如下的形式:
main函数返回的时候,内存自动被智能指针释放。
添加删除操作:
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 75 void remove(GTreeNode<T>* node, GTree<T>*& ret) 76 { 77 ret = new GTree<T>(); 78 79 if( ret == NULL ) 80 { 81 THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create tree..."); 82 } 83 else 84 { 85 if( root() == node ) 86 { 87 this->m_root = NULL; 88 } 89 else 90 { 91 LinkList<GTreeNode<T>*>& child = dynamic_cast<GTreeNode<T>*>(node->parent)->child; 92 93 child.remove(child.find(node)); 94 95 node->parent = NULL; 96 } 97 98 ret->m_root = node; 99 } 100 } 101 public: 102 bool insert(TreeNode<T>* node) 103 { 104 bool ret = true; 105 106 if( node != NULL ) 107 { 108 if( this->m_root == NULL ) //如果待插入节点的父节点为空,则这个节点将为根节点 109 { 110 node->parent = NULL; 111 this->m_root = node; 112 } 113 else 114 { 115 GTreeNode<T>* np = find(node->parent); 116 117 if( np != NULL ) 118 { 119 GTreeNode<T>* n = dynamic_cast<GTreeNode<T>*>(node); 120 121 if( np->child.find(n) < 0 ) 122 { 123 np->child.insert(n); 124 } 125 } 126 else 127 { 128 THROW_EXCEPTION(InvalidParameterException, "Invalid parent tree node..."); 129 } 130 } 131 } 132 else 133 { 134 THROW_EXCEPTION(InvalidParameterException, "Parameter node cannot be NULL ..."); 135 } 136 137 return ret; 138 } 139 140 bool insert(const T& value, TreeNode<T>* parent) 141 { 142 bool ret = true; 143 144 GTreeNode<T>* node = GTreeNode<T>::NewNode(); 145 146 if( node != NULL ) 147 { 148 node->value = value; 149 node->parent = parent; 150 151 insert(node); 152 } 153 else 154 { 155 THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); 156 } 157 158 return ret; 159 } 160 161 //删除的节点的子节点我们还需要处理,因此要返回删除节点的指针,这样有机会对里面的元素做进一步操作 162 SharedPointer< Tree<T> > remove(const T& value) 163 { 164 GTree<T>* ret = NULL; 165 166 GTreeNode<T>* node = find(value); 167 168 if( node == NULL ) 169 { 170 THROW_EXCEPTION(InvalidParameterException, "can not find the node ..."); 171 } 172 else 173 { 174 remove(node, ret); 175 } 176 177 return ret; 178 } 179 180 SharedPointer< Tree<T> > remove(TreeNode<T>* node) 181 { 182 GTree<T>* ret = NULL; 183 184 node = find(node); 185 186 if( node == NULL ) 187 { 188 THROW_EXCEPTION(InvalidParameterException, "parameter node is invalid ..."); 189 } 190 else 191 { 192 remove(dynamic_cast<GTreeNode<T>*>(node), ret); 193 } 194 195 return ret; 196 } 197 198 GTreeNode<T>* find(const T& value) const // 返回GTreeNode,赋值兼容性 199 { 200 return find(root(), value); 201 } 202 203 GTreeNode<T>* find(TreeNode<T>* node) const 204 { 205 return find(root(), dynamic_cast<GTreeNode<T>*>(node)); 206 } 207 208 GTreeNode<T>* root() const 209 { 210 return dynamic_cast<GTreeNode<T>*>(this->m_root); 211 } 212 213 int degree() const 214 { 215 return 0; 216 } 217 int count() const 218 { 219 return 0; 220 } 221 222 int height() const 223 { 224 return 0; 225 } 226 227 void clear() 228 { 229 free(root()); 230 231 this->m_root = NULL; 232 } 233 234 ~GTree() 235 { 236 clear(); 237 } 238 }; 239 240 } 241 242 #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.remove(‘D‘); 46 47 //用链表来验证我们的插入操作,从下至上遍历 48 49 const 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 }
结果如下:
第二个测试程序:
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 SharedPointer<Tree<char>> p = t.remove(t.find(‘D‘)); 46 47 //用链表来验证我们的插入操作,从下至上遍历 48 49 const char* s = "KLFGMIJ"; 50 51 for( int i = 0; i < 7; i++ ) 52 { 53 TreeNode<char>* node = p->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 }
结果如下:
可以看到返回了子树,子树中的结点我们都能访问到。
小结:
以上是关于第五十六课 树中结点的删除操作的主要内容,如果未能解决你的问题,请参考以下文章