代码随想录:二叉树2-4

144.二叉树的前序遍历

题目

        给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

代码(递归)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        //list保存遍历后的节点数据
        List<Integer> list = new ArrayList<Integer>();
        //调用前序递归
        preOrder(root, list);
        return list;

    }
    //递归的参数是树的根节点指针+存储遍历节点的数据
    public void preOrder(TreeNode root, List<Integer> list){
        //递归终止条件是节点指针为空,如果是空没有其余操作直接返回
        if(root == null){
            return;
        }
        //想清楚一层遍历的流程是先访问并获取中元素,再访问左子,再访问右子
        list.add(root.val);  //获取中
        preOrder(root.left,list); //访问左子
        preOrder(root.right,list); //访问右子
    }
}

代码(迭代)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        //list保存遍历后的节点数据
        List<Integer> list = new ArrayList<Integer>();
        Stack<TreeNode> stack = new Stack();

        //这个必须要写,不然后边cur.val会报错NullPointerException
        if(root == null){
            return list;
        }

        //根节点入栈
        stack.push(root);

        while(!stack.isEmpty()){
            TreeNode cur = stack.pop();  //栈顶,中间节点1出栈
            list.add(cur.val); //中间节点1add
            //右子节点3入栈
            if(cur.right != null){
                stack.push(cur.right);
            }
            //左子节点2入栈
            if(cur.left != null){
                stack.push(cur.left);
            }
        }
        return list;

    }
    
}

总结

1.递归的核心要确定三个点:

        ①递归函数的形参是什么,用到什么参数:根节点指针+遍历返回的数据列表

        ②递归的终止条件是什么:访问到空节点

        ③递归的一层是什么逻辑:先获取中间节点元素,再访问左子孩子,最后访问右子孩子。

2.迭代法的逻辑如下:

        中间节点先入栈,然后中间节点出栈时,连续执行三个操作,add中,如果右子节点非空把右进栈,如果左子节点非空把左进栈。

        以123为例,1作为根节点(中间节点)先入栈。

        然后中间节点1出栈,cur指向中间节点1,第一步先访问元素,把cur.val加入到list结果集,第二步,判断右子节点3非空,右子节点3进栈,第三步,判断左子节点2非空,左子节点2入栈。

        当栈非空时,不断的出栈,把出栈节点作为中间节点。然后节点2出栈,把cur.val的2加入到list结果集,访问左右节点都为空,空节点不入栈。

        当栈非空时,不断的出栈,把出栈节点作为中间节点。然后节点3出栈,把cur.val的3加入到list结果集,访问左右节点都为空,空节点不入栈。

        最后,栈空了,访问结束。list结果集里面是123。

94.二叉树的中序遍历

题目

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

代码(递归)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        inOrder(root,list);
        return list;

    }
    public void inOrder(TreeNode root, List<Integer> list){
        if(root == null){
            return;
        }
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right, list);
    }
}

代码(迭代)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();

        if(root == null){
            return list;
        }

        //当前节点cur指向根节点
        TreeNode cur = root;

        //当栈非空or当前节点非空
        while(cur != null || !stack.isEmpty()){
            //如果当前节点(中),就入栈,然后往左边走
            if(cur != null){
                stack.push(cur);
                cur = cur.left;  //一开始会走到最左下的空节点
            }
            //如果当前节点cur是空(左),就出栈访问(中间),然后走右下
            else{
                cur = stack.pop();
                list.add(cur.val);
                cur = cur.right;
            }
        }
        return list;
    }
    
}

总结

        中序迭代的核心逻辑是,先让cur指向根节点,然后如果cur不为空,就让cur进栈,相当于中间节点入栈,然后cur = cur.left,让cur不断走到树的最左下部分。当cur是空,说明走到了最左下的空节点,此时出栈,栈顶元素作为中间节点,需要add到list,此时左和中都处理完了,要继续访问右子树,让cur = cur.right.

        以1234为例,根节点是1,cur=1,cur不为空,就让cur=1进栈,cur = cur.left = 2.

        cur=2不为空,2进栈,cur = cur.left = 4。

        cur=4不为空,4进栈,cur = cur.left,此时cur指向的左子树最下面节点4的左空节点。

        当cur为空时,说明左子节点时空,此时栈顶元素4就是中间节点,则出栈并访问4,然后访问4的右节点。也是空,继续出栈,cur=2,访问节点2,2继续网右边走,走到空,继续出栈,cur=1,访问节点1,继续让1右边走,1走到3,cur=3,3不为空,就让3进栈,然后走3的左子空,3出栈并访问,cur指向3的右子空节点。

        此时,cur为指向的最右下的空节点,栈也为空,结束循环。1234的树中序输出4213。

145.二叉树的后序遍历

题目

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 

代码(递归)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        postOrder(root,list);
        return list;

    }
    public void postOrder(TreeNode root, List<Integer> list){
        if(root == null){
            return;
        }
        postOrder(root.left, list);
        postOrder(root.right, list);
        list.add(root.val);
    }
}

代码(迭代)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();

        //如果树为null,直接返回空list
        if(root == null){
            return list;
        }

        //根节点1先进栈
        stack.push(root);

        while(!stack.isEmpty()){

            //中间节点出栈
            TreeNode cur = stack.pop();
            //中间节点访问
            list.add(cur.val);

            //左子节点非空,则入栈
            if(cur.left != null){
                stack.push(cur.left);
            }
            //右子节点非空,则入栈
            if(cur.right != null){
                stack.push(cur.right);
            }
        }
        //前序的结果是123,调整前序左右子树进栈顺序的结果是132
        //把132,reverse一下,正好是231,是后序结果
        Collections.reverse(list);
        return(list);

    }
    
}

总结

        后序的迭代法其实和前序原理一样,前序是先拿中间节点访问,然后右左进栈,出栈是正好是中左右的顺序。后序把子节点的进栈顺序变为左右进栈。出栈就是中右左的顺序。最后,反转一下,就是左右中的顺序,后序完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

守岁白驹hh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值