数据结构考试前闲的蛋疼,整理课本。

结点建立

struct node
{int v;struct node* left, *right;int flag; //后序遍历
};
node * root;

中序遍历

模拟深搜过程,在第一次回溯的时候输出,即为中序遍历

 1 stack<node *> Q1;
 2     node * pre = root;
 3     while (1)
 4     {
 5         while (pre!=NULL)
 6         {
 7             Q1.push(pre);
 8             pre = pre->left;
 9         }
10         // 一直往左走
11         do
12         {
13             pre = Q1.top();
14             cout << pre->v<<" ";Q1.pop();
15         }while(pre->right==NULL&&!Q1.empty());
16         // 回溯到能往左走
17         if (pre->right==NULL) break;
18         // 结束的条件是 回溯到 队列为空了,还没找到能往左走的结点
19         // PS:结束上述循环的两种情况,①队列为空 ②回溯到能走的结点
20         pre = pre->right;
21     }
22     cout << endl;

中序遍历非递归

先序遍历

模拟深搜过程,在第一次加入栈的时候输出

 1 //与中序遍历相当类似
 2 stack<node *> Q3;
 3      pre = root;
 4     while (1)
 5     {
 6         while (pre!=NULL)
 7         {
 8             cout << pre->v<<" ";Q3.push(pre);
 9             pre = pre->left;
10         }
11         do
12         {
13             pre = Q3.top();
14             Q3.pop();
15         }while(pre->right==NULL&&!Q3.empty());
16         if (pre->right==NULL) break;
17         pre = pre->right;
18     }
19     cout << endl;
20
21 先序遍历非递归

先序遍历非递归

后序遍历

和以上两个遍历的区别是

中序遍历和先序遍历,节点输出位置容易判断

先序是:在加入新节点之前

中序是:在加入右儿子之前或没有右儿子时

而对于后序遍历

没有右儿子或右儿子已经被遍历完成

中序遍历在第一次回溯之后,完全可以将根节点pop,这样就会避免重复访问,并且也已经输出了。但是对于后序遍历,是在第二遍回溯之后输出,所以不能pop。正因如此,回溯过程无法判断当前节点是第几次回溯,所以需要一个标志变量FLAG。

 1 stack<node *> Q2;
 2     pre = root;
 3     while (1)
 4     {
 5         while (pre!=NULL)
 6         {
 7             Q2.push(pre);
 8             pre = pre->left;
 9         }
10         //一直往左走
11         while(!Q2.empty()&&(pre = Q2.top())&&(pre->right==NULL||pre->flag == 1))
12         {
13             cout << pre->v<<" ";
14             Q2.pop();
15         }
16         // 回溯到能往右走,不能往右走的原因有,没有右儿子,右结点已经被访问
17         // do-while 和 while 的区分!
18         if (Q2.empty()) break;
19         // 搜索结束条件
20         pre->flag = 1;
21         pre = pre->right;
22     }
23     cout << endl;

后序遍历非递归

刚写完博客,想了一会,发现可以不用FLAG,但是需要再开一个栈来维护。

中心思想就是,后序遍历的第二次(从右结点)回溯输出和没有右儿子,都可以总结为:不能再走了就输出!

那么将深搜顺序(按先序遍历压栈)一直压入另一个栈中,当一个节点无路可走了那么输出。

那么问题来了,怎么根据一个新栈来判断他是否无路可走了呢?

直接贴代码:

 1 stack <node *> Q1;
 2     stack<node *> Q3;
 3     pre = root;
 4     node * outp ;
 5     node * Before_out;
 6     int cnt = 0;
 7     while (1)
 8     {
 9         cnt++;
10         while (pre!=NULL)
11         {
12             Q1.push(pre);
13             Q3.push(pre);
14             pre = pre->left;
15         }
16         do
17         {
18             pre = Q1.top();
19             Q1.pop();
20         }while(pre->right==NULL&&!Q1.empty());
21         // 对一个节点进行dfs到最深,并回溯。直到遇见有右儿子的节点
22         // 可以证明对于pre来说,她的左儿子没有一个点有右儿子,并且左儿子全都位于Q3中
23         while(!Q3.empty()&&(outp = Q3.top())&& (outp -> right == NULL || outp -> right == Before_out  ) )
24               {
25                   cout << outp->v <<" ";
26                   Q3.pop();
27                   Before_out = outp;
28               }
29         //上述循环,会把pre那一堆没有右儿子的(左儿子生的后代)全部倒序(回溯顺序)输出
30         if (pre->right==NULL) break;
31         pre = pre->right;
32         //之后Q3中会存着pre pre->right;
33         //当处理完pre->right(假设已经处理完成,或假设压根pre->right就只一个节点),之后将会 倒序输出这两个点!
34          // cout << endl; 用打印标记理解更好
35     }
36     cout << endl;

非递归非FLAG后序遍历

并且可以看出,外层循环次数是右儿子个数+1;

转载于:https://www.cnblogs.com/HITLJR/p/6241499.html

二叉树遍历非递归写法相关推荐

  1. 二叉树前序、中序、后序遍历非递归写法的透彻解析

    前言 在前两篇文章二叉树和二叉搜索树中已经涉及到了二叉树的三种遍历.递归写法,只要理解思想,几行代码.可是非递归写法却很不容易.这里特地总结下,透彻解析它们的非递归写法.其中,中序遍历的非递归写法最简 ...

  2. 创建的二叉树后续非递归遍历结果为_一入递归深似海,从此offer是路人

    前言 今天我们来总结二叉树的前中后序以及层次遍历的递归与非递归的写法.我们都知道二叉树遍历的递归写法很简单,但是面试的时候面试官往往考察的不是我们递归的写法,他们满怀期待你写出非递归的解法,而当你只会 ...

  3. 4.二叉树的先序、中序以及后序遍历的递归写法与非递归写法(LeetCode第94、144、145题)

    一.递归法 这次我们要好好谈一谈递归,为什么很多同学看递归算法都是"一看就会,一写就废". 主要是对递归不成体系,没有方法论,每次写递归算法 ,都是靠玄学来写代码,代码能不能编过都 ...

  4. 转载:二叉树的前中后和层序遍历详细图解(递归和非递归写法)

    二叉树的前中后和层序遍历详细图解(递归和非递归写法) Monster_ii 2018-08-27 17:01:53 50530 收藏 403 分类专栏: 数据结构拾遗 文章标签: 二叉树 前序 中序 ...

  5. 二叉树的前序、中序、后序遍历(递归、非递归写法)

    文章目录 一.什么是二叉树? 二.二叉树的基本概念 三.二叉树的三种遍历方式 1.前序遍历(preordertraversal) 1.中序遍历(inordertraversal) 1.后序遍历(pos ...

  6. 【二叉树Java】二叉树遍历前序中序后序遍历的非递归写法

    本文主要介绍二叉树前序中序后序遍历的非递归写法 在探讨如何写出二叉树的前序中序后序遍历代码之前,我们先来明确一个问题,前序中序后序遍历根据什么区分? 二叉树的前序中序后序遍历,是相较根节点说的.最先遍 ...

  7. 多叉树的前序遍历_二叉树的非递归遍历的思考

    封面图来自wikipedia 1 简介 二叉树的深度优先遍历(前序遍历.中序遍历.后序遍历)是一个比较基本的操作.如果使用递归的做法,很容易写出相应的程序:而如果使用非递归的做法,虽然也能写出相应的代 ...

  8. 树:二叉树的非递归遍历算法

    二叉树的递归遍历 二叉树的递归遍历算法,写法很简单,比如说前序遍历树,如下: //前序遍历 void PreOrderTraverse(BiTree tree) {if (NULL != tree){ ...

  9. 刷题:二叉树的非递归遍历方式

    二叉树的非递归的遍历方式 上篇博客记录了二叉树的递归遍历方式以及根据二叉树的遍历结果还原二叉树的内容. 本篇博客记录二叉树的非递归的遍历方式. 二叉树的非递归遍历需要借助栈来实现,而且三种遍历的方式的 ...

  10. 二叉树的非递归遍历(c/c++)

    由于递归算法相对于非递归算法来说效率通常都会更低,递归算法会有更多的资源需要压栈和出栈操作(不仅仅是参数,还有函数地址等)由于编译器对附加的一些栈保护机制会导致递归执行的更加低效,使用循环代替递归算法 ...

最新文章

  1. 【Python小游戏】扫雷游戏竟有世界排行榜,中国90后00后霸占半壁江山?
  2. 天池 在线编程 最频繁出现的子串(字符串哈希)
  3. 这款Java性能调优工具,真的很强!
  4. 明明选的是个人用途,为什么会被检测商用?
  5. JS输出内容为[object Object]
  6. Linux内核学习笔记一
  7. vb从入门到精通_干货|让你 ArcGIS Engine从入门到精通的22个视频
  8. javascript new对象的过程
  9. .\Flash\Blinky.axf: Error: L6200E: Symbol SysTick_Handler multiply defined (by hal_cm0.o and blinky.
  10. 54 小明的存钱计划
  11. Android imageview 圆形头像
  12. 10 大话设计模式C++实现之模板方法模式
  13. 为什么深圳成指关注度远远小于上证指数?
  14. 人脸识别经典开源项目
  15. 2022年下半年软件评测师考试真题一些回忆
  16. VC++ Hook截取鼠标点击窗口消息的问题!全局钩子
  17. BLAST中的E值的理解
  18. 【GitHubDailyShare】在 Linux 上无缝运行 macOS 系统软件
  19. 学习笔记:AC+AP配置:同一个SSID,多个AP的无缝连接漫游。
  20. (前端)html与css,html 5、h、p标签,与_img路径

热门文章

  1. windows 服务的安装与卸载之bat脚本命令
  2. react native 使用TabNavigator编写APP底部导航
  3. 快速生成plist文件
  4. vs2013使用remote debug
  5. Win2003安装VS.NET2005sp1出现1718错误的解决方案
  6. 求问模式达人,静态类可否代替单件?
  7. Everybody was kung-fu fighting
  8. [贪心][模拟] Jzoj P5811 简单的填数
  9. 最大值、数据排序、九九乘法表、杨辉三角
  10. String及其常用API