【编程题 递归+非递归】BM25 二叉树的后序遍历(详细注释 易懂)

题目描述

题目链接:二叉树的后序遍历_牛客题霸_牛客网 (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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值