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

【左程云算法018】二叉树遍历非递归写法及复杂度分析

文章目录

  • 用栈实现二叉树先序遍历
      • 大体思路:
      • 先序完整代码
  • 用栈实现二叉树中序遍历
      • 大体思路
      • 中序完整代码
  • 用两个栈实现二叉树后序遍历
      • 后序 完整代码
  • 用一个栈实现二叉树后序遍历
      • 大体思路
      • 后序 完整代码
  • 分析时间复杂度
  • 分析空间复杂度

在这里插入图片描述

视频链接
【算法讲解018【入门】二叉树遍历的非递归实现和复杂度分析】

用栈实现二叉树先序遍历

leecode144.二叉树的前序遍历

大体思路:

先把头结点压到栈里面去,每次弹出一个节点,先压右再压左在这里插入图片描述
为什么先压右?因为你要想先弹出左,先压入右那么左就能先弹出。
在这里插入图片描述
模拟过程:

public static void preOrder(TreeNode head){
if(head !=null){
Stack<TreeNode> stack = new Stack<>();//先创建一个栈
stack.push<head>;//把头结点放进去

在这里插入图片描述

while(!stack.isEmpty()){
head = stack.pop();
System.out.print(head.val+" ");

当栈里面不为空时头结点弹出并打印(将1弹出并打印)在这里插入图片描述

右不为空先把右压入到栈里面(把3压入)

if(head.right!=null){//右不为空先压入右
stack.push(head.right);
}

在这里插入图片描述
左不为空把左压入栈里(把2压入)

if(head.left!=null){
stack.push(head.left);
}

在这里插入图片描述
第一次循环结束
第二次循环判断

while(!stack.isEmpty()){
head = stack.pop();
System.out.print(head.val+" ");

依旧非空,所以将2设为头节点(子树的头)
将2弹出并打印
在这里插入图片描述
同样先压右再压左

代码略
将5压入
将4压入
在这里插入图片描述
第二次循环完毕
第三次循环开始
依旧非空
弹出4
右没有 不执行(没数字可压入)
左没有 不执行(没数字可压入)
第三次循环完毕
第四次循环开始
依旧非空
弹出5
右没有 不执行(没数字可压入)
左没有 不执行(没数字可压入)
第四次循环完毕
第五次循环开始
依旧非空
弹出3
压入7
压入6
…(省略)

先序完整代码

public static void preOrder(TreeNode head){
if(head !=null){
Stack<TreeNode>stack = new Stack<>();
stack.push(head);
while(!stack.isEmpty){
head = stack.pop();
System.out.print(head.val+" ");
if(head.right !=null{
stack.push(head.right);
}
if(head.left !=null{
stack.push(head.left);
}
}
System.out.println();
}
}

用栈实现二叉树中序遍历

leecode 94. 二叉树的中序遍历

大体思路

  • 1)来到头,让左边界进栈,直到左边没数可进。
  • 2)从栈弹出节点 打印 节点的右树重复步骤一
    *3) 直到没有子树且栈空了

举个例子
完成1)
现在头是1,让左边界都进栈(即1 2 4)
在这里插入图片描述
2)
弹出4 ,打印4,4的子树是5, 5要重复步骤1,所以将5,6压入在这里插入图片描述
重复
再弹出6,打印6,6没右树
再弹出5,打印5,5没右树
再弹出2,打印2,2有右树,7入栈
再弹出7,打印7,7没右树。
再弹出1,打印1,1有右树,3入栈在这里插入图片描述
再弹出3,打印3,3有右树,8入栈
…(省略)
在这里插入图片描述
为什么中序要这样?

  • 对于任何一个节点,因为刚开始把左节点全都压入了,所以对于任何一个节点必须把左边都处理干净了才轮到自己,然后才轮到自己的右边。所以这样才能实现中序遍历。

跟着代码再完整过一次

public static void inOrder(TreeNode head){
if(head ! = null){
Stack<TreeNode>stack = new Stack<>();

在这里插入图片描述
第一次循环 栈为空但是头节点不为空
所以把head压入 head往左边去(1进去 head变为2)

while(!stack.isEmpty()||head!=null){
if(head!=null){
stack.push(head);
head = head.left;}

在这里插入图片描述s
第二次循环 还是不为空 所以2压入 head来到4在这里插入图片描述
第三次循环 还是不为空 所以4压入 head来到null在这里插入图片描述
这不就是在压入自己的左边界吗
因为head为空 但是stack不为空 所以继续
第四次循环
属于else里面的 4弹出 head等于弹出的 所以head从null变为4 弹出就打印 打印完head跑到右孩子上去(null)

else{
head = stack.pop();
System.out.print(head.val+" ");
head = head.right;
}
}
System.out.println();
}

在这里插入图片描述
是空又要弹出,2弹出,head变为2,弹出就打印,head又往右树去所以head是5在这里插入图片描述
又一次循环(head不为空的条件)
所以把5的左边界都压进去(本题只能光压个5),最后head又来到了5的左孩子null上面
在这里插入图片描述
继续下一次循环
从栈里弹出 head回到5 打印5 head来到5的右树上,又是null。

继续下一次循环
从栈里弹出1 head回到1 打印1 head来到1的右树上,是3.

继续下一次循环
…(省略)

你发现了什么?
是不是每次头结点都会先把左边都遍历完,没得遍历的时候会指向空,一指向空下一步就是弹出并打印,然后来到这个节点的右树…

中序完整代码

public static void inOrder(TreeNode head){
if(head !=null){
Stack<TreeNode> stack = new Stack<>();
while(!stack.isEmpty()  || head !=null){
if(head !=null){//压入左边界
stack.push(head);
head = head.left;
}else{//如果节点是空 那么就让栈里弹出一个并打印 让节点是这个弹出的数的右树
head = stack.pop();
System.out.print(head.val+" ");
head = head.right;
}
}
System.out.println();
}

用两个栈实现二叉树后序遍历

leecode 145. 用两个栈实现二叉树的后序遍历
可以用先序改造成后序!
先序是 中 左 右
后序是 左 右 中

先序会
那先序’呢? 中 右 左
是不是也会啦 循环里面调换一下顺序即可

那中右左你都会了
反转一下是不是就是左右中?是不是就是后序

问题来了 怎么反转
之前是弹出就打印
现在我不打印了
我把它再放到另一个栈里去
就可实现逆序!

后序 完整代码

public static void posOrderTwoStacks(TreeNode head){
if(head !=null){
Stack<TreeNode> stack = new Stack<>();
Stack<TreeNode> collect = new Stack<>();
stack.push(head);
while(!stack.isEmpty()){
head = stack.pop();
collect.push(head);
if(head.left!=null){
stack.push(head.left);
}
if(head.right !=null){
stack.push(head.right);
}
}
//从colect栈中依次弹出并打印
while(!collect.isEmpty()){
System.out.print(collect.pop().val+" ");
}
System.out.println();

用一个栈实现二叉树后序遍历

leecode 145. 用两个栈实现二叉树的后序遍历

大体思路

public static void posOrderOneStack(TreeNode h){
if(h!=null){
Stack<TreeNode> stack = new Stack<>();
stack.push(h);

1是头节点 不为空
1进栈
在这里插入图片描述

//如果始终没有打印过节点,h就一直是头节点
//一旦打印过节点,h就变成打印节点
//之后h的含义:上一次打印的节点

现在头节点还是1

while(!stack.isEmpty()){
TreeNode cur = stack.peek();//peek了一下,但是现在头节点依旧是1
if(cur.left != null && h! = cur.left && h!=cur.right){
//把左孩子压进来
stack.push(cur.left);}
else//...待补充

第一次循环结束
第二次循环开始
2进栈 现在顶部节点是2,头节点是1
在这里插入图片描述
第二次循环结束
第三次循环开始
4入栈
第三次循环结束
在这里插入图片描述

//接上文
else if(cur.right !=null && h!=cur.right){
//有右树且右树没处理过
stack.push(cur.right);
}else{
//左树 右树 没有 或者 都处理过了
System.out.print(cur.val + " ");
h = stack.pop();
}
}
System.out.println();
}

打印4 把4弹出 h变为4(其实在这里h相当于一个哨兵,标记他有没有被处理)
在这里插入图片描述
此时又是一次循环 现在栈顶是2 头节点是4
2的左孩子是头节点 所以去else if对应的行
把5压入
在这里插入图片描述
又是一次循环 在else语句
打印5 弹出5 h变为5
栈顶是2
左树右树都处理过了 所以符合else语句
2打印 2弹出 h来到2
在这里插入图片描述
至此,2整棵树弄完了
继续循环
栈顶为1,左树处理完了 符合else if语句
3压入
在这里插入图片描述
又一次循环
栈顶为3 左树未处理 把6压入
在这里插入图片描述
又一次循环 栈顶为6
6无左树无右树 符合else语句 6弹出并作为h
在这里插入图片描述

也就是说
第一个if的含义
我有左树 刚处理过的既不是我的左 也不是我的右
左树才会压入栈
第二个if的含义
我有右树 刚处理过的不是我的右树
右树才会入栈
在这里插入图片描述
7作为一个子树都处理过了(因为无左也无右) 所以打印7弹出7标记7
在这里插入图片描述
栈顶来到3
3左树右树都处理过了
所以打印3 弹出3 标记3
在这里插入图片描述
最后处理1 左树处理完了右树处理完了 所以打印1 弹出1 标记1

后序 完整代码

public static void posOrderOneStack(TreeNode h){
if(h!=null){
Stack<TreeNode> stack = new Stack<>();
stack.push(h);
while(!stack.isEmpty()){
TreeNode cur = stack.peek();//peek了一下,但是现在头节点依旧是1
if(cur.left != null && h! = cur.left && h!=cur.right){
//把左孩子压进来
stack.push(cur.left);}
else if(cur.right !=null && h!=cur.right){
//有右树且右树没处理过
stack.push(cur.right);
}else{
//左树 右树 没有 或者 都处理过了
System.out.print(cur.val + " ");
h = stack.pop();
}
}
System.out.println();
}

分析时间复杂度

递归方法 任何一个节点只要它不空 就会来到它三次 如果有n个节点 那复杂度就是O(n)
非递归方法 也是O(n),因为每个节点入栈和出栈的次数是有限次

分析空间复杂度

递归方法O(h) h是树的高度
非递归方法O(h) h是树的高度
因为最多栈里压h层 数出栈了它这个空间还能复用

http://www.dtcms.com/a/416512.html

相关文章:

  • 网站建设资料准备标准大连做网站大公司
  • 网站设计四项原则网站建设企业哪家好
  • 安康优质网站建设方案网站建设套模板视频
  • ccv.gapi_wip_gst_GStreamerPipeline | setNumThreads | no attribute ‘object‘
  • t型网站域名和版面鑫牛元网站建设
  • 苏州公司技术支持 苏州网站建设网站改版404页面
  • 湖南营销型网站建设推广设计好用的网站
  • 网站流量排名查询工具引擎seo如何优化
  • vite快速上手
  • 大网站服务器维护费用wordpress多语言企业网站
  • 温州制作网站软件上海到北京飞机几小时
  • 泉州 网站建设wordpress手机版地址
  • 做网站专题页的字大小是多少企业文化墙设计图
  • 贵阳网站建设管理河南app开发公司
  • 扁平化色彩网站wordpress 星 评分
  • 微信企业微网站中国数据网站空间
  • 做网站 先备案么前端做网站难吗
  • P1063 [NOIP 2006 提高组] 能量项链
  • 网站备案医疗保健审批号是什么在线式crm
  • 崆峒区建设局网站珠海市住房和城乡建设部网站
  • React学习(二)
  • 京东网站建设思维导图网站中的幻灯片ie6显示 ie7如何兼容
  • 什么网站做海宁的房产好网站维护费一年多少钱
  • 房产中介网站开发做韩国护的网站
  • 建网站软件网站后台怎么修改代码
  • 信息门户网站建设电商型网站
  • 专业做w7系统的网站上海设立企业网站
  • C4D储卡器底部塑料壳建模之外部解析
  • 建设电商平台网站企业 wordpress 主题
  • 汕头网站设计浩森宇特wordpress插件收录