非递归遍历二叉树

1.前言

​ 总所周知,二叉树的遍历分为先序遍历、中序遍历和后序遍历。遍历的顺序不同,则结果不同。而遍历方法也分递归和非递归。而二者的复杂度相同:时间复杂度为O(nlgn),空间复杂度为O(n)

​ 虽然递归的二叉树逻辑简单,但是通过递归调用可能会浪费多余的栈空间资源,因此非递归遍历也是十分有用的,相比起递归遍历,其会占用更少的栈资源。

2.非递归遍历的实现

​ 非递归遍历二叉树是通过循环来实现的,在逻辑上相比起递归要稍微复杂一些,需要借用到stack(栈)数据结构。因为遍历时必须根节点往子节点循环,因此我们需要某类容器来存储上次循环节点的值,而栈这种类型数据结构恰恰能满足我们所需。

​ 那么如何利用栈来实现二叉树的非递归遍历呢?

​ 如果一个二叉树只有三个节点:根节点、左子节点、右子节点。那么所谓的先序遍历,就是先输出根节点、再输出左子节点、再输出右子节点;同理中序遍历,是输出左子节点、根节点、右子节点;后序遍历…。那么我们可以将三个节点按照我们想要的顺序依次推入栈中,再弹出,就能对三个节点进行先、中、后序遍历。例如:

struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;};//三节点二叉树的先序输出
stack<TreeNode *> sta;
//中序和后序,只需要修改入栈的顺序
sta.push(root->right);
sta.push(root->left);
sta.push(root);
cout<<(sta.top())->val<<endl;
sta.pop();
cout<<(sta.top())->val<<endl;
sta.pop();
cout<<(sta.top())->val<<endl;
sta.pop();

​ 那假设现在给这个二叉树的左子节点赋予左、右子节点,使得二叉树变为5节点的二叉树。那么原来3节点二叉树的先序遍历:根、根左、根右——就变成:根、根左、左左、左右、根右。会发现原来根节点的左子节点扩展成了三个,也就是包含了其左右子节点,而如果只看左子节点和它的子节点会发现,它们三个的顺序也是:根、左、右。

​ 我们现在可以得出一个结论,所谓的先序遍历、中序遍历、后序遍历不过是对一个节点以及它的左右子节点的遍历顺序罢了。那么我们把每三个节点:根、左、右当做一个整体,根据弹出栈的顺序,在循环遍历的时候将三个节点入栈,就能得到我们想要的遍历顺序。以下提供一种循环遍历二叉树的方法:

​ 该方法需要注意的一点:每个节点会被弹出两次栈,第一次被弹出是为了将左右子节点或者父节点入栈,第二次弹出是真正将其输出。

//先序非递归遍历
sta.push(root);//先把根节点入栈
map<TreeNode*,bool> m;//定义一个键值对,用来判别该节点是否弹出过一次栈
m.insert(make_pair(root,false));//如果值为false,则未被弹出过栈
while(!sta.empty())//如果栈空,则说明遍历完成
{p = sta.top();//弹出栈if(p == NULL)continue;sta.pop();if(m[p] == true)//如果值为true,则之前被弹出过一次栈{vec.push_back(p->val);}else{if(p->right != NULL)//右子节点入栈{m.insert(make_pair(p->right,false));sta.push(p->right);}if(p->left != NULL)//左子节点入栈{m.insert(make_pair(p->left,false));sta.push(p->left);}m[p] = true;//第一次弹出栈,将值设为truesta.push(p);//再次入栈}
}

​ 以上是先序非递归遍历,如果需要中序、后序遍历,只需要修改入栈顺序。

非递归遍历二叉树实现和理解相关推荐

  1. 【转】更简单的非递归遍历二叉树的方法

    [转]更简单的非递归遍历二叉树的方法 解决二叉树的很多问题的方案都是基于对二叉树的遍历.遍历二叉树的前序,中序,后序三大方法算是计算机科班学生必写代码了.其递归遍历是人人都能信手拈来,可是在手生时写出 ...

  2. 更简单的非递归遍历二叉树

    解决二叉树的很多问题的方案都是基于对二叉树的遍历.遍历二叉树的前序,中序,后序三大方法算是计算机科班学生必写代码了.其递归遍历是人人都能信手拈来,可是在手生时写出非递归遍历恐非易事.正因为并非易事,所 ...

  3. 数据结构专题 | 先序非递归遍历二叉树

    先序非递归遍历二叉树,主要是利用了栈的先进后出原理,用一个栈即可实现该算法,下面我们一起来看一下如何来实现吧 目录 先序建立二叉树 先序递归遍历二叉树 先序非递归遍历二叉树 先序建立二叉树 在进行先序 ...

  4. 中序非递归遍历二叉树

    二叉树的递归算法虽然简单,但是会导致时间复杂度比较高,下面给大家带来用栈实现的二叉树非递归算法 首先定义好二叉树,和元素类型为二叉树的栈 typedef struct BiTNode{TElemTyp ...

  5. 非递归遍历二叉树(算法导论第三版第十章10.4-5)

    非递归遍历二叉树(算法导论第三版第十章10.4-5) template<typename T> void TraverseBinaryTreeNonRecursive(BinaryTree ...

  6. 非递归遍历二叉树(后序遍历)

    非递归遍历二叉树(后序遍历) 在二叉树的遍历中,分为递归遍历与非递归遍历.非递归遍历的执行效率较高,时间复杂度小,因此采用非递归遍历有利于提高代码运行效率. //后序遍历非递归实现 void Post ...

  7. C++实现递归,非递归遍历二叉树(前序,中序,后序)

    初学二叉树那会儿,始终掌握不好二叉树的遍历方法,更认为非递归遍历晦涩难懂没有掌握的意义.实际上非递归的遍历方法很有用处,由于每次递归都需要将函数的信息入栈,当递归层数太深很容易就导致栈溢出,所以这个时 ...

  8. 数据结构_非递归遍历二叉树(C语言)

    数据结构总目录 非递归遍历二叉树 1. 图文解析 对于链式二叉树,如果要用非递归的方式进行前.中.后序遍历,则需要借助一个栈实现,而层序遍历则需要借助队列来实现. 构建如下二叉树: 非递归先序遍历 ( ...

  9. 更简单的非递归遍历二叉树的方法

    解决二叉树的很多问题的方案都是基于对二叉树的遍历.遍历二叉树的前序,中序,后序三大方法算是计算机科班学生必写代码了.其递归遍历是人人都能信手拈来,可是在手生时写出非递归遍历恐非易事.正因为并非易事,所 ...

最新文章

  1. Qlik与百度开放云建立战略联盟,让中国企业通过强大的可视化分析看到数据背后的整个故事...
  2. uiiamgeview 设置圆角
  3. 互联网1分钟 |1228
  4. JavaScript计算两个文本框内数据的乘积(四舍五入保留两位小数)
  5. 2015 多校第三场
  6. C语言之在结构体里面放很多函数指针
  7. windows下eclipse调试hadoop详解
  8. linux下网络监听与发送数据包的方法(即libpcap、libnet两种类库的使用方法)
  9. 报道称奈雪的茶通过港交所聆讯 回应:以公司经监管机构批准的公告为准
  10. C#面向对象15 多态
  11. Android_L(64bit) 模拟器配置及创建项目
  12. TCP三次握手连接和TCP四次挥手及大量TIME_WAIT解决方法:
  13. unity可以直接转h5吗_瞎折腾:用Unity撸纯HTML5移动游戏/应用
  14. Apache Camel,Spring Boot 实现文件复制,转移 (转)
  15. java 有意思面试题_一些JAVA中有趣的面试题
  16. sql: sql developer tunnel转接
  17. 计算机安全韩亮,韩亮
  18. Axure8.0汉化包+注册码
  19. C++学习第六天——数组
  20. 系统时钟的时钟源选择

热门文章

  1. linux下java调用matlab方案
  2. S32K144 串口通信
  3. 自定义设置电脑屏保(.scr文件)
  4. Java实现 LeetCode 66 加一
  5. ISACA将于2016年6月更新CISA考试大纲
  6. 车用计算机电路板,汽车电脑板的原理与检修方法
  7. AM5728(AM5708)开发实战之安装Debian 10桌面操作系统
  8. 关于Epidata软件中 .QES文件出现‘乱码伴随编号前面多个n’问题的解决办法
  9. 【LeetCode 5-中等】最长回文子串(高清截图)
  10. 西加加C++入门语法(与派森python相对应)