二叉树的前序,中序,后序遍历(递归写法+迭代写法)

leetcode 144 前序遍历

leetcode 94 中序遍历

leetcode 145 后序遍历

要求输出元素顺序

一、递归写法

        1.1 前序遍历:根,左,右

        思路:第一次访问结点,就要把结点放入结果序列,然后先访问左结点,再访问右结点,依次递归下去。

        

class Solution {
    public void preOrder(TreeNode node,List result){
        if(node==null) return;//递归出口为访问到空结点
        result.add(node.val);//第一次访问后立刻添加
        preOrder(node.left,result);
        preOrder(node.right,result);
    }
   public List preorderTraversal(TreeNode root) {
        List x=new ArrayList();
        preOrder(root,x);
        return x;
    }
}

  1.2  中序遍历:左,根,右

        思路:第二次访问结点(回溯时),把结点放入结果集合。

class Solution {
    public void inOrder(TreeNode node,List result){
        if(node==null) return;
        inOrder(node.left,result);//一直访问到最后一个左结点
        result.add(node.val);//回溯时,将本结点加入结果序列
        inOrder(node.right,result);//然后递归地访问右结点
    }
    public List inorderTraversal(TreeNode root) {
        List x=new ArrayList<>();
        inOrder(root,x);
        return x;
    }
}

1.3 后序遍历:左,右,根

        思路:左右结点访问完,第三次访问根结点时,把结点加入到结果序列中。

class Solution {
    public void postOrder(TreeNode node, List result){
        if(node==null) return;//访问到空结点返回
        //递归访问左结点前,是对根结点的第一次访问
        postOrder(node.left,result);
        //访问完左子树,回溯,是对根结点的第二次访问
        postOrder(node.right,result);
        //访问完右子树,回溯,是对根结点的第三次访问,把本结点的值放入结果序列
        result.add(node.val);
    }
    public List postorderTraversal(TreeNode root) {
        List x=new ArrayList<>();
        postOrder(root,x);
        return x;
    }
}

二、迭代法

递归法的原理是栈,先调用的会被放到栈底,回溯时最后被拿出调用,后调用的在栈顶,越靠近栈顶,回溯时越先被调用。

2.1 前序遍历(根,左,右)

        思路:根结点进栈,根结点出栈,右结点进栈,左结点进栈,左结点出栈,右结点出栈

        出栈顺序即为结果顺序

public List preorderTraversal(TreeNode root) {
        List x=new ArrayList<>();
        Stack stack=new Stack();
        if(root==null) return x;
        stack.push(root);
        while(!stack.empty()){
           TreeNode temp=stack.pop();//根元素出栈
           x.add(temp.val);//出栈的元素的值要放入结果序列中
           /*
                右结点先入栈,左结点后入栈,栈顶元素作为新的根结点在下次循环中先被弹出
                直到栈为空。(所有元素都进栈一次,出栈一次,出栈顺序即结果顺序)
           */
           if(temp.right!=null) stack.push(temp.right);
           if(temp.left!=null) stack.push(temp.left);
        }
        return x;
}

 2.2 后序遍历 (左,右,根)

        后序遍历其实和前序遍历正好反着

        思路:根进栈后,立刻出栈,先让左结点进,再让右结点进,然后右结点先出,左结点后              出。

        这样出栈顺序就变为了 根右左

       正好和我们想要的结果相反,

        把结果序列反转即可得到正确答案。

       

public List postorderTraversal(TreeNode root) {
        List x=new ArrayList<>();
        Stack stack=new Stack();
        if(root==null) return x;
        stack.push(root);
        while(!stack.empty()){
           TreeNode temp=stack.pop();//根元素出栈
           x.add(temp.val);//出栈的元素的值要放入结果序列中
           /*
                左结点先入栈,右结点后入栈,栈顶元素作为新的根结点在下次循环中先被弹出
                直到栈为空。(所有元素都进栈一次,出栈一次,出栈顺序反转即结果顺序)
           */
           if(temp.left!=null) stack.push(temp.left);
           if(temp.right!=null) stack.push(temp.right);
        }
        Collections.reverse(x);
        return x;
        
}

2.3 中序遍历(左,根,右)

思路:前序遍历的核心在于访问的元素和要放入结果序列的元素是同一个,而中序遍历的难点是访问的元素和放入结果序列的元素不是同一个,要一直访问到左边底部的元素,才开始出栈,放入结果序列。

public List inorderTraversal(TreeNode root) {
        List x=new ArrayList<>();
        Stack stack=new Stack();
        if(root==null) return x;
        TreeNode t=root;//t指向访问的元素,只有访问到左侧最底部的元素时才可以出栈
        //结束循环的条件其实只有栈为空(t!=null时表示还有元素可以入栈)
        while(t!=null||!stack.empty()){
           if(t!=null){
                stack.push(t);
                t=t.left;
           }else{
                TreeNode temp=stack.pop();
                x.add(temp.val);
                t=temp.right;
           }
            
        }
        return x;
        
}

参考文章:https://leetcode.cn/problems/binary-tree-postorder-traversal/solution/bang-ni-dui-er-cha-shu-bu-zai-mi-mang-che-di-chi-t/

你可能感兴趣的:(数据结构与算法,树,leetcode,java,数据结构,算法)