当前位置: 首页 > news >正文

关于二叉树的遍历梳理(递归、非递归、线索二叉树)

  二叉树作为的基本数据结构,应用广泛,在生活中处处可见,而遍历二叉树在二叉树应用中十分常见。与线性存储结构不同,二叉树每个节点都有可能有两棵子树,从二叉树的存储结构可知:

1 template <typename T>
2 typedef struct BiTNode
3 {
4     T data;
5     struct BiTNode *lchild, *rchild;
6 }BiTree;

  根节点、左子树、右子树——二叉树的基本组成单位。那么,根据的递归的思想(数据结构严蔚敏版):当一个复杂的问题可以分解成若干子问题来处理时,其中某些子问题与原问题有相同的特征属性,则可利用和原问题相同的分析处理方法;反之,这些子问题解决了,原问题也就迎刃而解了。递归遍历就是将原二叉树分解为若干子树。

 1 template <typename T>
 2 int PreOrderTraverse(BiTree & Tree, int (*Visit)(T & e))
 3 {
 4     //Visit函数理解为打印e,若成功返回1,否则返回0。
 5     if (Tree) //判断树是否为空树
 6     {
 7         if (Visit(Tree.data)) //打印节点数据
 8             if (PreOrderTraverse(Tree.lchild, Visit) //向左遍历
 9                 if (PreOrderTraverse(Tree.rchild, Visit) return 1; //左遍历退出遍历右侧
10         return 0;
11     }
12     else return 1;
13 }

  从递归工作过程可以看出,第i层栈顶,左子树返回i-1层进行右子树遍历,而右子树返回则直接删除栈顶返回(这取决于遍历的方式:先序遍历,中序遍历,后序遍历)。

  由此,可以模仿递归算法写出非递归算法的遍历函数。

  

 1 template <typename T>
 2 void PreOrderTraverse(BiTNode & Tree, int (*Visit(T e))
 3 {
 4     InitStack(S); //初始化栈S
 5     BiTree p; 
 6     Push(S, Tree); //根节点入栈
 7     while (!StackEmpty(S))
 8     {
 9         while (GetTop(S, p) && p) 
10         {
11             Visit(p.data);
12             Push(S,(p.lchild); //左子树压栈
13         } //while
14         Pop(S, *p); //空指针出栈,用p返回其节点---------1
15         if (!StackEmpty(S))
16         {
17             Pop(S, p); //-------------------------------2
18             Push(S,p.rchild);
19         } //if
20     } //while
21 }

  使用栈来管理遍历的过程,由于是先序遍历,所以每向左压一次栈时便Visit一次节点,到达最左端时(依次从根节点Visit了左子树各子树的根节点)向右压栈,到达右叶子节点时回退,由于第17行的退栈,会使得栈顶变为上上层的根节点。也就是遍历右子树时不需要保存当前层的根指针,可直接修改栈顶的指针。说的有些不清楚,但这和递归算法思路一致,不过是自己管理栈的进出。

  注意,粗略一看可能会产生疑惑:Pop退栈p多退了一层。这里第一个Pop函数退出空指针,p是其返回值也为空,经过第二个Pop函数p才为有效栈顶。就比如,小红组装某个物件将步骤列了个清单,她将要着手去做这一步骤时,将该步骤从清单划去,划去的这一时刻是上一件事产生的影响。

  这两种遍历是对非线性结构进行线性化操作,引用双向链表的前驱后继的思想,修改二叉树的现有数据结构,新增两个标志域——LTag和RTag。

 1 template <typename T>
 2 typedef struct BiThrNide
 3 {
 4     T data;
 5     int LTag,RTag;
 6     BiThrTree *lchild, *rchild;
 7 }BiThrTree;
 8 
 9 void InOrderTraverse(BiThrTree & Tree, int (*Visit(T e)))
10 {
11     //Tree的lchild指向树的根节点
12     //标志符LTag、RTag为0则指针域指向孩子节点,为1指向前驱或后继
13     BiThrTree p;
14     while (p != Tree)
15     {
16         while (p.LTag == 0) p = p.lchild; //向左遍历
17         if (!Visit(p.data)) exit(ERROR);
18         while (p.RTag == 1 && p.rchild != Tree) //没有右子树,指向后继,且后继不为头结点
19         {
20             P = P.rchild; //向后继遍历
21             Visit(p.data);
22         }
23         p = p.rchild;
24     }
25 }

  由于线索二叉树存储结构较普通二叉树丰满,所以遍历过程也更为好理解,此处不做赘述。

  

转载于:https://www.cnblogs.com/jinnianlover/p/8635532.html

相关文章:

  • JSONObject和JSONArray区别及基本用法
  • Idea中使用git
  • 怎么爆加密过后的前端JS
  • 201521123016《Java程序设计》第14周学习总结
  • datenode节点超时时间设置,Hadoop启动不正常,HDFS冗余数据块的自动删除,NameNode安全模式问题,ntp时间服务同步,机架感知配置...
  • 航天科工发布中国首个工业互联网云平台
  • sql语句查询最新记录
  • Gurobi + CVX + Matlab
  • MooseFS源代码分析(二)
  • 积累各种好的链接
  • 开肩
  • 2018网易在线笔试题
  • 面试题:Student s = new Student();在内存中做了哪些事情?即创建一个对象做了哪些事情...
  • Unity Shader-后处理:简单均值模糊
  • AppScan扫描
  • Android组件 - 收藏集 - 掘金
  • Brief introduction of how to 'Call, Apply and Bind'
  • git 常用命令
  • javascript从右向左截取指定位数字符的3种方法
  • Javascript基础之Array数组API
  • js 实现textarea输入字数提示
  • laravel 用artisan创建自己的模板
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • rc-form之最单纯情况
  • Vue全家桶实现一个Web App
  • 测试如何在敏捷团队中工作?
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 三分钟教你同步 Visual Studio Code 设置
  • 写给高年级小学生看的《Bash 指南》
  • 正则表达式小结
  • 翻译 | The Principles of OOD 面向对象设计原则
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • #13 yum、编译安装与sed命令的使用
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (LeetCode) T14. Longest Common Prefix
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (附源码)spring boot校园拼车微信小程序 毕业设计 091617
  • (三)mysql_MYSQL(三)
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (十六)Flask之蓝图
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • ***利用Ms05002溢出找“肉鸡
  • .htaccess配置重写url引擎
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .NET Core 2.1路线图
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .NET高级面试指南专题十一【 设计模式介绍,为什么要用设计模式】
  • @NoArgsConstructor和@AllArgsConstructor,@Builder