力扣144二叉树的前序遍历、94二叉树书的中序遍历、145二叉树的后序遍历

144二叉树的前序遍历

1、递归法

前序遍历要求遍历的顺序是根节点、左节点、右结点,于是我们在递归算法中将加入节点的操作放在遍历左节点和遍历右节点前面,遍历左节点也要放到遍历右节点前,因为递归其实是深度优先的,即进入了一个递归一定要等它完成这个递归过程后再来返回程序继续执行接下来的操作,于是按照前序遍历要求,我们需要遍历完左节点再遍历右节点。

/**
 * 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<Integer> res=new ArrayList<>();
    access(root,res);
    return res;
    }
    public void access(TreeNode root,List<Integer> res){
        if(root==null)return;
        res.add(root.val);
        access(root.left,res);
        access(root.right,res);
    }
}

2、迭代法

遇到根节点直接将它加入结果数组里面,然后将此节点入栈,遍历其左节点直至当前节点没有左结点,然后从栈中出结点,当前出栈的结点是已经加入了结果数组里面的结点,在上面遍历左节点的过程中,其实当前的根节点和左节点已经遍历完了,我们接下来就遍历它的右结点。

不理解的话可以看看下面的图来帮助理解

下图是从根结点A遍历到子节点G时,结果数组与栈的情况

接下来我们将G出栈,然后遍历它的右结点,发现他没有右节点我们就继续出栈D,然后遍历他的右节点,右结点遍历完,发现它没有左节点和右节点,于是继续出栈B,遍历B的右节点,按照上面描述的步骤如此往复,我们最终可以得到结果数组为A、B、D、G、H、C、E、I、F。

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> res=new ArrayList<>();
    Stack<TreeNode> s1=new Stack<>();
    while(root!=null||!s1.empty()){
     while(root!=null){
         res.add(root.val);
         s1.push(root);
         root=root.left;
     }
     root=s1.pop();
     root=root.right;
    }
    return res;
}
}

94二叉树的中序遍历

1、递归法

二叉树前中后遍历递归法的思路都是一致,只是加入结点操作的语句位置不同。

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res=new ArrayList<>();
        access(root,res);
        return res;
    }
    public void access(TreeNode root,List<Integer> res){
        if(root==null)return ;
      access(root.left,res);
       res.add(root.val);
      access(root.right,res);
    }
}

2、迭代法

中序遍历要求的顺序为左根右,我们遍历根节点到最左结点的时候不应该在第一个循环里面直接将根结点的值加入结果数组,我们应该先将左节点的值加入结果数组,所以将节点的值加入结果数组的语句放在root为空然后赋值为出栈的节点之后即可,不理解的话可以按照图来自己实现理解。

下图是从根结点A遍历到子节点G时,结果数组与栈的情况

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res=new ArrayList<>();
        Stack<TreeNode> s1=new Stack<>();
        while(root!=null||!s1.empty()){
            while(root!=null){
                s1.push(root);
                root=root.left;
            }
            root=s1.pop();
            res.add(root.val);
            root=root.right;
        }
        return res;
    }
   
}

145二叉树的后序遍历

1、递归法

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> res=new ArrayList<>();
    access(root,res);
    return res;
    }
    public void access(TreeNode root,List<Integer> res){
        if(root==null)return ;
        access(root.left,res);
        access(root.right,res);
        res.add(root.val);
    }
}

2、迭代法

后序遍历的顺序要求是左右根,后续遍历的迭代法实现起来比前两个稍微复杂一点,这里我用图一步一步解释,根据要求的顺序,我们首先还是要遍历到最左节点,将它的值加入结果数组,然后再按照左右根的顺序遍历,if语句条件的root.right==null与root.right==prevaccess是为了判断当前节点的右节点遍历过没有,因为根节点的遍历顺序要在右节点后。

比如说如下图,当将G节点加入结果数组里面后,按照程序执行,我们出栈D节点,D节点的右节点即不为空也不等于前面值加入结果数组的节点G,于是将D节点重新入栈,然后令当前节点等于D节点的右孩子节点,继续循环,H节点为叶子节点,于是第一个while(root!=null)实际就是将root节点入栈然后跳出循环再出栈这个节点即H,H节点的右孩子节点为空,于是将H节点的值加入结果数组,并让prevaccess节点等于H节点,继续循环,下一次出栈的节点就是D,D的右节点H的值已经在上一个循环中加入了结果数组,即root.right==prevaccess,此时再将D节点的值加入结果数组,由此我们可以看出,实现了左节点右节点根节点的遍历顺序。如此循环往复即可实现二叉树的后序遍历。

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> res=new ArrayList<>();
    Stack<TreeNode> s1=new Stack<>();
    TreeNode prevaccess=null;
   while(root!=null||!s1.empty()){
    while(root!=null){
        s1.push(root);
        root=root.left;
    }
    root=s1.pop();
    if(root.right==null||root.right==prevaccess){
        res.add(root.val);
        prevaccess=root;
        root=null;
    }else{
        s1.push(root);
     root=root.right;
    }
   }
    return res;
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值