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

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

 

小结:

技术分享图片

 

技术分享图片

 

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

第五十五课 linux系统调优 之cpu内存网络I/O

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

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

第六十五课 二叉树中属性操作的实现

《剑指offer》第五十五题II:平衡二叉树

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