二叉树遍历算法之三:后序遍历
后续遍历的递归实现
后续遍历指的是先访问节点的左右孩子,最后访问节点本身。所以使用后序遍历得到的结果的最后一个节点就是根节点。采用后续遍历的具体步骤如下:
- 先访问根节点,如果有左孩子,进入第二步;如果有右孩子,进入第三步
- 对左孩子继续判断其是否有左孩子,直到某节点的左孩子为空,设为cur节点
- 对右孩子继续判其是否有左孩子,直到某个节点的左孩子为空,设为curR节点
- cur节点访问之后,访问其双亲节点的右孩子,如果其双亲节点的右孩子不为空的话。接着访问cur节点的双亲节点,设为curP节点。
- cur节点的双亲节点访问结束之后,继续访问curP节点的右孩子(如果不为空的话),接着访问curP节点本身
- 重复以上过程直到根节点
- 继续访问根节点的右孩子,回到第三步,访问curR节点之后,访问其双亲节点的右孩子(如果有的话)
- 最后访问curR的双亲节点本身
重复以上过程直到访问根节点,访问结束
比如下面的二叉树后序遍历的访问结果是:24,15,5,7,6,30,9,28,11,10,8
那么使用递归实现的代码如下:
public void postOrderTraverse(TreeNode node){if(node == null) return;postOrderTraverse(node.left);postOrderTraverse(node.right);System.out.print(node.val + " ");}
后续遍历的非递归实现
后续遍历的非递归实现与前面的前序遍历和中序遍历的方式有一些不同,由于根节点是最后访问的,在访问的时候创建一个栈保存遍历的结果还不够,所以需要使用一个辅助栈来记住每个访问节点的双亲节点。先看代码:
public void postOrderTraverse2(TreeNode node){Stack<TreeNode> s1 = new Stack<TreeNode>();//创建栈s2的目的在于记住每个访问的节点Stack<Integer> s2 = new Stack<Integer>();//如果栈s2的栈顶是1,标识当前访问的节点Integer i = new Integer(1);while(node != null || !s1.isEmpty()){while(node != null){s1.push(node);s2.push(0);node = node.left;}//这个循坏的目的是对栈s2栈顶为1时对应的栈s1的栈顶元素进行访问while(!s1.isEmpty() && s2.peek().equals(i)){s2.pop();System.out.print(s1.pop().val + " ");}//访问左子树到头后,就可以访问其右孩子了if(!s1.isEmpty()){s2.pop();s2.push(i);node = s1.peek();node = node.right;}}}
下面具体说明具体的执行过程:
根节点8不为空,放入栈s1中,同时往栈s2中放入0,由于8的左孩子是6不为空,所以继续放入栈s1中,同时往栈s2中放入0,直到节点15,由于其左孩子为空,所以第一个循坏结束,现在两个栈的情况是这样的:
由于栈s2的栈顶元素是0,不符合,所以第二个循环不执行,直接跳到if判断语句,把栈s2的栈顶元素弹出,同时压入元素1,并且取出栈s1的栈顶元素,也就是15,访问15的右孩子24
第二次循环开始,仍然满足第一个循环,于是把24放入栈s1,同时在栈s2压入一个0,由于24是叶子节点,所以第一个循环结束。前两次操作执行完毕后,两个栈的情况是这样的:
由于栈s2的栈顶元素仍然是0,所以第二个循环继续跳过,到if判断语句。弹出栈s2的栈顶元素0,同时压入元素1。并让当前节点指向24的右孩子
第三次循环开始,由于24没有右孩子,所以将跳过第一个循环,现在栈s2的栈顶元素是1,所以弹出栈s1的栈顶元素和栈s2的栈顶元素1,并输出24。执行以上两步之后,两个栈时这样的:
继续执行第二个while循环(因为栈s2的栈顶仍然是1),弹出1,弹出15,接着输出15。循环结束
进入if判断语句,弹出栈顶元素0,压入元素1,并让当前节点指向5的右孩子。这时两个栈时的情况如下:
第四次循环开始,由于5没有右孩子,第一个循环跳过,这时栈s2的栈顶是1,所以将弹出1,弹出5,接着输出5。这时两个栈是这样的:
9. 继续执行if语句,栈s2弹出0,压入1,并让当前节点指向6的右孩子,也就是节点7
10. 开始第五次循环,首先第一个循环,将7压入栈s1中,同时栈s2压入0。栈s2的栈顶元素是0,不满足第二个循环的条件,执行if语句。此时两个栈的情况如下:
11. 弹出0,压入1,并让当前节点指向7的右孩子
12. 开始第六次循环,7没有右孩子,直接执行第二个循环,将执行两次,栈s1分别弹出7和6,并输出依次输出7和6,同时栈s2分别弹出两个1,最后栈的情况是这样的:
13. 执行if语句,弹出0,压入1,并让当前节点指向8的右孩子,也就是10。后面的过程与上面类似,看图就好了
二叉树遍历算法之三:后序遍历相关推荐
- 数据结构与算法(java):树-二叉树(二叉查找树(BST)、线索化二叉树、哈夫曼树、平衡二叉树【AVL】、二叉树的前中后序遍历)
二叉树 1.定义 二叉树 就是度不超过2的树(每个结点最多只有两个子结点).如图 2.特殊二叉树 满二叉树 当二叉树的每一个层的结点树都达到最大值,则这个二叉树就是满二叉树. 完全二叉树 叶结点只能出 ...
- Java版二叉树的前序遍历查找、中序遍历查找和后序遍历查找
文章收藏的好句子:任何挫折,如果无法彻底击败你,那一定会使你更强. 目录 1.二叉树的节点查找 1.1 前序遍历查找 1.2 中序遍历查找 1.3 后序遍历查找 1.二叉树的节点查找 1.1 前序遍 ...
- 【数据结构】二叉树的前中后序遍历
二叉树的三种遍历 1. 创建一棵简单的二叉树 1.1 二叉树结构体实现 1.2 创造一个二叉树结点的函数 1.3 手动创造一棵二叉树 2.为什么要遍历? 3.最重要的知识:由二叉树引出的子问题分析 4 ...
- 图解二叉树的先中后序遍历
二叉树前中后序介绍 对于一个二叉树而言,前序(根左右),中序(左根右),后序(左右根) . 可以简单这样理解: 所有的顺序都是以根在根.左.右 三个元素中的位置来决定的.根在前面,就是前序(根左右), ...
- 二叉树(前序遍历序列、中序遍历序列、后序遍历序列、层次遍历序列、深度、叶子数)
Description 已知二叉树的一个按前序遍历输入的字符序列,如abc,de,g,f, (其中,表示空结点).请建立二叉树,并输出建立二叉树的前序遍历序列.中序遍历序列.后序遍历序列.层次遍历序列 ...
- 二叉树的前,中,后序遍历(思路分析) [Java][数据结构]
二叉树的前,中,后序遍历(思路分析) 前序遍历: 先输出父节点, 再遍历左子树和右子树 中序遍历: 先遍历左子树, 再输出父节点,再遍历右子树 后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点 ...
- 二叉树的前中后序遍历(考试常考)
二叉树遍历的概念 二叉树的遍历是按某种规则对二叉树的每个节点均只被访问一次,根据根节点访问位置的不同分为三种:先序遍历(根左右).中序遍历(左根右).后序遍历(左右根). 由于树是通过 ...
- Java二叉树的前中后序遍历
Java二叉树的前中后序遍历 1.前序遍历 1.1前序遍历概念 1.2前序遍历习题 2.中序遍历 2.1中序遍历概念 2.2中序遍历习题 3.后续遍历 3.1后序遍历概念 3.2后序遍历习题 大家好, ...
- C++实现已知二叉树前序遍历和中序遍历,求后序遍历
C++实现已知二叉树前序遍历和中序遍历,求后序遍历 一.基本概念 1.先序遍历(NLR)可以确定二叉树的父子结点: 2.中序遍历(LNR)可以确定二叉树的左右子树: 3.后序遍历(LRN)可以确定二叉 ...
- tree traversal (树的遍历) - postorder traversal (后序遍历)
tree traversal (树的遍历) - postorder traversal (后序遍历) 1. tree traversal - 树的遍历 二叉树的遍历 (traversing binar ...
最新文章
- YARN-2.7.3-源码分析系列2:启动脚本原理的分析
- vue component created没有触发_详解在Vue中使用TypeScript的一些思考(实践)
- 常见HTTP状态码列表
- fedora如何隐藏顶部状态栏_藏在 iOS 13 里的 9 个隐藏小技巧
- datatable转化泛型
- Could not load oracle/sql/converter_xcharset/lx20354.glb.
- 技术实操丨HBase 2.X版本的元数据修复及一种数据迁移方式
- python库的安装方法_Python库的安装方法
- Pandas Series
- 高斯伪谱法 matlab,Gauss 高斯伪谱法求解的 ,希望对大家有用的!代码比较复杂,但是可以运行。 matlab 263万源代码下载- www.pudn.com...
- Python抓取小说
- 每天Leetcode 刷题 初级算法篇-杨辉三角
- 当你发现你的Alter报错的时候请看看是不是粗心了
- 我与刘强东的故事:他的1000亿和我的5000万(转超级表格)
- SEM和SEO的区别
- 网页表格线框html,网页设计表格单元格线条及边框设置
- ribbon实现负载均衡
- 使用unity完成简单的打地鼠游戏2D制作
- 企业邮箱怎么发邮件,又如何进行查询呢?
- LTspice使用第三方spice模型进行仿真
热门文章
- java导入hbase_如何用java导入hbase.dat文件
- linux sdl 显示内存,Linux系统:如何解决sdl安装遇到的问题
- chown: `mysql#039;: invalid user_centos无法正常启动,报chown: invalid user:'root:root'
- python读取word文件内容_[python]读取word文档中的数据,整理成excel表
- android 登录 service_如何优雅的实现自己的Android组件化改造?
- hdu 3879 Base Station
- Java线程池ThreadPoolExecutor使用与解析
- Vue2.0七——生命周期
- linux程序设计——多线程(第十二章)
- 三目(三元)运算符??::的形式