题目描述
题目链接:二叉树的后序遍历_牛客题霸_牛客网 (nowcoder.com)
给定一个二叉树,返回他的后序遍历的序列。
后序遍历是值按照 左节点->右节点->根节点 的顺序的遍历。
数据范围:二叉树的节点数量满足 0≤n≤100 ,二叉树节点的值满足 1≤val≤100 ,树的各节点的值各不相同
示例1
输入:
{1,#,2,3}返回值:
[3,2,1]说明:
如题面图
示例2
输入:
{1}返回值:
[1]
题目解读:
说到二叉树的后序遍历,很多人应该闭着眼睛也能做出来,确实,递归形式的二叉树遍历太简单了。但是如果面试官让你写非递归的呢,如果没有准备过,突然写,还是挺难的,那就来学习一下吧。
解题思想:
后序遍历就是 左 右 根 ,依次遍历嘛,那就按这个思想做。递归版本的,我就不说了,主要说非递归版本的,一开始就是 从根节点一直进行左子树遍历,把遍历结果放到栈里面,遍历完成后,开始从栈里面弹出一个节点,这个节点当然就是 左子树里最下面的那个节点,弹出它以后(它是左子树最下面的子树,所以它肯定就没有左子树了),不能直接访问它里面的值,因为后序遍历是 左 右 根, 要先确认它有没有右子树,如果它没有右子树,那就直接记录它的 val值,然后继续弹出。如果它有右子树,那先把它入栈,再去遍历它的右子树,右子树(假设只有一个右节点,以下图node节点为例)遍历完之后,然后继续弹出,此刻先弹的是它的右子树,它的右子树没有左右节点,那就直接访问,然后再次弹出node节点,此时又遇到这个问题,node节点有右子树,怎么避免再次去遍历,那就是用一个节点标记。就是在把 它的右子树 弹出访问后,进行标记,然后node 弹出后,一看它的右子树被标记了,就可以访问node节点了。 非递归遍历确实有点难哈,我叨叨了这么多,哈哈!
代码注释(递归):
import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* public TreeNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return int整型一维数组
*/
public int[] postorderTraversal (TreeNode root) {
// write code here
ArrayList<Integer> list =new ArrayList<>();
postorder(list,root);
int[] arr =new int[list.size()];
for(int i=0;i< arr.length;i++){
arr[i]= list.get(i);
}
return arr;
}
public void postorder(ArrayList<Integer>list,TreeNode root){
if(root == null)
return;
postorder(list,root.left);
postorder(list,root.right);
list.add(root.val);
}
}
代码注释(非递归):
import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* public TreeNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return int整型一维数组
*/
public int[] postorderTraversal (TreeNode root) {
// write code here
ArrayList<Integer>list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
// 这是标记节点
TreeNode pre = null;
// 一开始 栈为空,但是根节点不为空,以根节点为条件,进入循环
while(!stack.isEmpty() || root!= null){
while(root != null){
stack.push(root);
root = root.left;
}
TreeNode node =stack.pop();
// 要么当前节点没有右子树,要么右子树之前被访问了
if(node.right == null || node.right == pre){
list.add(node.val);
// 对弹出的右子树访问后 进行标记,供下次遍历到右子树的父节点时 参考
pre = node;
}else{
stack.push(node);
root = node.right;
}
}
int[] arr = new int[list.size()];
for(int i=0;i< list.size();i++){
arr[i] = list.get(i);
}
return arr;
}
}