第五十八课 树形结构的层次遍历

通用树结构是一种容器,里面装有数据元素,我们有遍历元素的需求。

非线性决定了树中的每个结点没有固定的编号方式。

将队列中队首的指针定义成遍历时的游标,根节点进入队列后,游标指向根节点。

队头元素弹出,队首的指针就指向了别的元素,这就相当于移动了游标。

添加遍历相关的程序:

  1 #ifndef GTREE_H
  2 #define GTREE_H
  3
  4 #include "Tree.h"
  5 #include "GTreeNode.h"
  6 #include "Exception.h"
  7 #include "LinkQueue.h"
  8
  9 namespace DTLib
 10 {
 11
 12 template < typename T >
 13 class GTree : public Tree<T>
 14 {
 15 protected:
 16     LinkQueue<GTreeNode<T>*> m_queue;
 17
 18     GTree(const GTree<T>&);
 19     GTree<T>& operator = (const GTree<T>&);
 20
 21     GTreeNode<T>* find(GTreeNode<T>* node, const T& value) const
 22     {
 23         GTreeNode<T>* ret = NULL;
 24
 25         if( node != NULL )
 26         {
 27             if( node->value == value )
 28             {
 29                 return node;
 30             }
 31             else
 32             {
 33                 for(node->child.move(0); !node->child.end() && (ret == NULL); node->child.next())
 34                 {
 35                     ret = find(node->child.current(), value);
 36                 }
 37             }
 38         }
 39
 40         return ret;
 41     }
 42
 43     GTreeNode<T>* find(GTreeNode<T>* node,  GTreeNode<T>* obj) const
 44     {
 45         GTreeNode<T>* ret = NULL;
 46
 47         if( node == obj )
 48         {
 49             return node;
 50         }
 51         else
 52         {
 53             if( node != NULL )
 54             {
 55                 for( node->child.move(0); !node->child.end() && (ret == NULL); node->child.next())
 56                 {
 57                     ret = find(node->child.current(), obj);
 58                 }
 59             }
 60         }
 61
 62         return ret;
 63     }
 64
 65     void free(GTreeNode<T>* node)
 66     {
 67         if( node != NULL )
 68         {
 69             for(node->child.move(0); !node->child.end(); node->child.next())
 70             {
 71                 free(node->child.current());
 72             }
 73
 74             if( node->flag() )
 75             {
 76                 delete node;
 77             }
 78         }
 79     }
 80
 81     void remove(GTreeNode<T>* node, GTree<T>*& ret)
 82     {
 83         ret = new GTree<T>();
 84
 85         if( ret == NULL )
 86         {
 87             THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create tree...");
 88         }
 89         else
 90         {
 91             if( root() == node )
 92             {
 93                 this->m_root = NULL;
 94             }
 95             else
 96             {
 97                 LinkList<GTreeNode<T>*>& child = dynamic_cast<GTreeNode<T>*>(node->parent)->child;
 98
 99                 child.remove(child.find(node));
100
101                 node->parent = NULL;
102             }
103
104             ret->m_root = node;
105         }
106     }
107
108     int count(GTreeNode<T>* node) const
109     {
110         int ret = 0;
111
112         if( node != NULL )
113         {
114             ret = 1;
115
116             //node如果没有孩子,则for不执行
117             for(node->child.move(0); !node->child.end(); node->child.next())
118             {
119                 ret += count(node->child.current());
120             }
121         }
122
123         return ret;
124     }
125
126     int height(GTreeNode<T>* node) const
127     {
128         int ret = 0;
129
130         if( node != NULL )
131         {
132             for(node->child.move(0); !node->child.end(); node->child.next())
133             {
134                 int h = height(node->child.current());
135
136                 if( ret < h )
137                 {
138                     ret = h;
139                 }
140             }
141
142             ret = ret + 1;
143         }
144
145         return ret;
146     }
147
148     int degree(GTreeNode<T>* node) const
149     {
150         int ret = 0;
151
152         if( node != NULL )
153         {
154             ret = node->child.length();  //根节点的度数
155
156             for(node->child.move(0); !node->child.end(); node->child.next())
157             {
158                 int d = degree(node->child.current());
159
160                 if( ret < d )
161                 {
162                     ret = d;
163                 }
164             }
165         }
166
167         return ret;
168     }
169 public:
170     GTree()
171     {
172
173     }
174     bool insert(TreeNode<T>* node)
175     {
176         bool ret = true;
177
178         if( node != NULL )
179         {
180             if( this->m_root == NULL ) //如果待插入节点的父节点为空,则这个节点将为根节点
181             {
182                 node->parent = NULL;
183                 this->m_root = node;
184             }
185             else
186             {
187                 GTreeNode<T>* np = find(node->parent);
188
189                 if( np != NULL )
190                 {
191                     GTreeNode<T>* n = dynamic_cast<GTreeNode<T>*>(node);
192
193                     if( np->child.find(n) < 0 )
194                     {
195                         np->child.insert(n);
196                     }
197                 }
198                 else
199                 {
200                     THROW_EXCEPTION(InvalidParameterException, "Invalid parent tree node...");
201                 }
202             }
203         }
204         else
205         {
206             THROW_EXCEPTION(InvalidParameterException, "Parameter node cannot be NULL ...");
207         }
208
209         return ret;
210     }
211
212     bool insert(const T& value, TreeNode<T>* parent)
213     {
214         bool ret = true;
215
216         GTreeNode<T>* node = GTreeNode<T>::NewNode();
217
218         if( node != NULL )
219         {
220             node->value = value;
221             node->parent = parent;
222
223             insert(node);
224         }
225         else
226         {
227             THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ...");
228         }
229
230         return ret;
231     }
232
233     //删除的节点的子节点我们还需要处理,因此要返回删除节点的指针,这样有机会对里面的元素做进一步操作
234     SharedPointer< Tree<T> > remove(const T& value)
235     {
236         GTree<T>* ret = NULL;
237
238         GTreeNode<T>* node = find(value);
239
240         if( node == NULL )
241         {
242             THROW_EXCEPTION(InvalidParameterException, "can not find the node ...");
243         }
244         else
245         {
246             remove(node, ret);
247
248             m_queue.clear();
249         }
250
251         return ret;
252     }
253
254     SharedPointer< Tree<T> > remove(TreeNode<T>* node)
255     {
256         GTree<T>* ret = NULL;
257
258         node = find(node);
259
260         if( node == NULL )
261         {
262             THROW_EXCEPTION(InvalidParameterException, "parameter node is invalid ...");
263         }
264         else
265         {
266             remove(dynamic_cast<GTreeNode<T>*>(node), ret);
267
268             m_queue.clear();
269         }
270
271         return ret;
272     }
273
274     GTreeNode<T>* find(const T& value) const  // 返回GTreeNode,赋值兼容性
275     {
276         return find(root(), value);
277     }
278
279     GTreeNode<T>* find(TreeNode<T>* node) const
280     {
281         return find(root(), dynamic_cast<GTreeNode<T>*>(node));
282     }
283
284     GTreeNode<T>* root() const
285     {
286         return dynamic_cast<GTreeNode<T>*>(this->m_root);
287     }
288
289     int degree() const
290     {
291         return degree(root());
292     }
293     int count() const
294     {
295         return count(root());
296     }
297
298     int height() const
299     {
300         return height(root());
301     }
302
303     void clear()
304     {
305         free(root());
306
307         this->m_root = NULL;
308
309         m_queue.clear();
310     }
311
312     bool begin()
313     {
314         bool ret = ( root() != NULL );
315
316         if( ret )
317         {
318             m_queue.clear();
319             m_queue.add(root());
320         }
321
322         return ret;
323     }
324
325     bool end()
326     {
327         return (m_queue.length() == 0);
328     }
329
330     bool next()
331     {
332         bool ret = (m_queue.length() > 0);
333
334         if( ret )
335         {
336             GTreeNode<T>* node = m_queue.front();
337
338             m_queue.remove();  //将对头元素出队,相当于移动游标
339
340             for(node->child.move(0); !node->child.end(); node->child.next())
341             {
342                 m_queue.add(node->child.current());
343             }
344         }
345
346         return ret;
347     }
348
349     T current()
350     {
351         if( !end() )  //遍历的过程当中调用current函数才有意义
352         {
353             return m_queue.front()->value;
354         }
355         else
356         {
357             THROW_EXCEPTION(InvalidOperationException, "No value at current position...");
358         }
359     }
360
361     ~GTree()
362     {
363         clear();
364     }
365 };
366
367 }
368
369 #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     cout << t.degree() << endl;
46
47     for(t.begin(); !t.end(); t.next())
48     {
49         cout << t.current() << endl;
50     }
51
52     return 0;
53 }

结果如下:

小结:

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9692498.html

时间: 2024-10-08 14:08:56

第五十八课 树形结构的层次遍历的相关文章

第五十八课、自定义模型类(上)------------------狄泰软件学院

 一.自定义模型类 1.QStandardItemModel是一个通用的模型类 (1).能够以任意的方式组织数据(线程.非线性) (2).数据组织的基本单位为数据项(QStandardItem) (3).每一个数据项能够存储多个具体数据(附加数据角色) (4).每一个数据项能够对数据状态进行控制(可编辑.可选...) 2.Qt中的通用模型类QStandardItemModel (1).QStandardItemModel继承自抽象的模型类QAbstractItemModel (2).QStand

第五十八课 Openstack Neutron网络模型及Cinder基础及部署

OpenStack  Neutron网络模型详解 OpenStack  Cinder基础及部署

python五十八课——正则表达式(分组)

演示正则中的替换和切割操作:在这之前我们先学习一个分组的概念: 分组:在正则中定义(...)就可以进行分组,理解为得到了一个子组好处:1).如果正则中的逻辑比较复杂,使用分组就可以优化代码的阅读性(更有层级感)2).一旦进行了分组,在正则表达式的后半部分内容中很有可能需要引用子组中的内容: 一旦引用了组,那么这两部分的内容(值)就可以保持一致了 import re phone='62589999' regex=r'd{4}(d)r{3}' #r'...()...()...()..' print(

python五十八课——正则表达式(切割)

切割:split(regex,string):返回一个列表对象 import re str1='i love shenzhen so much' regex=r' +?' lt=re.split(regex,str1) print(lt) str2='dsafsa2341241dfakdsf34242dsafasfd______3214123fdsafas2131dsafas' regex=r'd+' lt=re.split(regex,str2) print(lt) ''' 补充案例:和替换有

python五十八课——正则表达式(替换)

替换:sub(regex,repl,string,count,[flags=0]): 替换数据,返回字符串(已经被替换完成后的内容)subn(regex,repl,string,count,[flags=0]): 替换数据,返回元祖对象,此元祖有两个元素 第一个元素记录了替换以后的字符串内容, 第二个元素记录了被替换的次数(count的值)参数:regex:正则规则(字符串)repl:需要被替换成的内容(new)string:需要被替换的内容(原串)count:需要被替换的个数,默认全部替换 i

NeHe OpenGL教程 第三十八课:资源文件

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十八课:资源文件 从资源文件中载入图像: 如何把图像数据保存到*.exe程序中,使用Windows的资源文件吧,它既简单又实用. 欢迎来到NeHe教程第38课.离上节课的写作已经有些时日了,加上写了一整天的code,也许笔头已经

NeHe OpenGL教程 第二十八课:贝塞尔曲面

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十八课:贝塞尔曲面 贝塞尔曲面: 这是一课关于数学运算的,没有别的内容了.来,有信心就看看它吧. 贝塞尔曲面 作者: David Nikdel ( [email protected] ) 这篇教程旨在介绍贝塞尔曲面,希望有比我更

NeHe OpenGL教程 第十八课:二次几何体

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第十八课:二次几何体 二次几何体: 利用二次几何体,你可以很容易的创建球,圆盘,圆柱和圆锥. 二次曲面是一种画复合对象的方法,这种方法通常并不需要很多的三角形.我们将要使用第七课的代码.我们将要增加7个变量以及修改纹理以增加一些变化

斯坦福第十八课:应用实例:图片文字识别(Application Example: Photo OCR)

18.1  问题描述和流程图 18.2  滑动窗口 18.3  获取大量数据和人工数据 18.4  上限分析:哪部分管道的接下去做 18.1  问题描述和流程图 图像文字识别应用所作的事是,从一张给定的图片中识别文字.这比从一份扫描文档中 识别文字要复杂的多. 为了完成这样的工作,需要采取如下步骤: 为了完成这样的工作,需要采取如下步骤: 1. 文字侦测(Text detection)——将图片上的文字与其他环境对象分离开来 2. 字符切分(Character segmentation)——将文