第五十六课 树中结点的删除操作

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 }

结果如下:

技术分享图片

 

可以看到返回了子树,子树中的结点我们都能访问到。

 

小结:

技术分享图片

 

 

技术分享图片

 

以上是关于第五十六课 树中结点的删除操作的主要内容,如果未能解决你的问题,请参考以下文章

代码随想录算法训练营第五十六天 | 583. 两个字符串的删除操作72. 编辑距离编辑距离总结

剑指offer五十六之删除链表中重复的结点

第五十四课 树中节点的插入操作

第五十七课 树中属性操作的实现

第五十五课 树中节点的清除操作

第五十三课 树中节点的查找操作