美文网首页
二叉树的前,中,后序遍历,以及层序遍历。

二叉树的前,中,后序遍历,以及层序遍历。

作者: 盼旺 | 来源:发表于2023-04-19 12:10 被阅读0次

https://leetcode.cn/problems/binary-tree-preorder-traversal/
https://leetcode.cn/problems/binary-tree-inorder-traversal/
https://leetcode.cn/problems/binary-tree-postorder-traversal/
https://leetcode.cn/problems/binary-tree-level-order-traversal/

简单的递归法

class Solution {
    private List<Integer> rr = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        helper(root);
        return rr;
    }

    public void helper(TreeNode t){
            if(t==null){
                return;
            }
            rr.add(t.val);
            helper(t.left);
            helper(t.right);
    }
}

class Solution {
    private List<Integer> rr = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        helper(root);
        return rr;
    }
    public void helper(TreeNode t){
            if(t==null){
                return;
            }
            helper(t.left);
            rr.add(t.val);
            helper(t.right);
    }
}

class Solution {
     private List<Integer> rr = new ArrayList<>();
    public List<Integer> postorderTraversal(TreeNode root) {
        helper(root);
        return rr;
    }
    public void helper(TreeNode t){
            if(t==null){
                return;
            }
            helper(t.left);
            helper(t.right);
            rr.add(t.val);
    }
}

利用栈的迭代

class Solution {
    private List<Integer> rr = new ArrayList<>();
    private Stack<TreeNode> stack = new Stack<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root==null){
            return rr;
        }
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode t = stack.pop();
            if(t==null){
                continue;
            }
            rr.add(t.val);
            stack.push(t.right);
            stack.push(t.left);
        }
        return rr;
    }
}

因为中序的根在中间,要先找到最左的节点,所以需要引入一个新的变量

栈S;
p= root;
while(p || S不空){
while(p){
p入S;
p = p的左子树;
}
p = S.top 出栈;
访问p;
p = p的右子树;
}

class Solution {
    private List<Integer> rr = new ArrayList<>();
    private Stack<TreeNode> stack = new Stack<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root==null){
            return rr;
        }
        TreeNode cur = root;
        while(!stack.isEmpty()||cur!=null){
            while(cur!=null){
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode node = stack.pop();
            rr.add(node.val);
            if(node.right!=null){
                cur = node.right;
            } 
        }
        return rr;
    }
}

前序遍历的过程 是 根左右。
将其转化成 根右左。也就是压栈的过程中优先压入左子树,在压入右子树。
然后将这个结果反向打印出来。

class Solution {
    private List<Integer> rr = new ArrayList<>();
    private List<Integer> rr2 = new ArrayList<>();
    private Stack<TreeNode> stack = new Stack<>();
    public List<Integer> postorderTraversal(TreeNode root) {
        if(root==null){
            return rr;
        }
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode t = stack.pop();
            if(t==null){
                continue;
            }
            rr.add(t.val);
            stack.push(t.left);
            stack.push(t.right);
        }
        for(int i=rr.size()-1;i>=0;i--){
            rr2.add(rr.get(i));
        }
        return rr2;
    }
}

颜色标记法

其核心思想如下:

使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
如果遇到的节点为灰色,则将节点的值输出。

class Solution {
    private List<Integer> rr = new ArrayList<>();
    private Stack<TreeNode> stack = new Stack<>();
    private Map<TreeNode,String> umap = new HashMap<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root==null){
            return rr;
        }
        stack.push(root);
        umap.put(root,"white");
        while(!stack.isEmpty()){
            TreeNode t = stack.pop();
            if(t==null){
                continue;
            }
            if(umap.get(t).equals("white")){
                umap.put(t,"grey");
                umap.put(t.right,"white");
                umap.put(t.left,"white");
                stack.push(t.right);
                stack.push(t.left);
                stack.push(t);
            }else{
                rr.add(t.val);
            }
        }
        return rr;
    }
}

class Solution {
    private List<Integer> rr = new ArrayList<>();
    private Stack<TreeNode> stack = new Stack<>();
    private Map<TreeNode,String> umap = new HashMap<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root==null){
            return rr;
        }
        stack.push(root);
        umap.put(root,"white");
        while(!stack.isEmpty()){
            TreeNode t = stack.pop();
            if(t==null){
                continue;
            }
            if(umap.get(t).equals("white")){
                umap.put(t,"grey");
                umap.put(t.right,"white");
                umap.put(t.left,"white");
                stack.push(t.right);
                stack.push(t);
                stack.push(t.left);
            }else{
                rr.add(t.val);
            }
        }
        return rr;
    }
}

class Solution {
    private List<Integer> rr = new ArrayList<>();
    private Stack<TreeNode> stack = new Stack<>();
    private Map<TreeNode,String> umap = new HashMap<>();
    public List<Integer> postorderTraversal(TreeNode root) {
        if(root==null){
            return rr;
        }
        stack.push(root);
        umap.put(root,"white");
        while(!stack.isEmpty()){
            TreeNode t = stack.pop();
            if(t==null){
                continue;
            }
            if(umap.get(t).equals("white")){
                umap.put(t,"grey");
                umap.put(t.right,"white");
                umap.put(t.left,"white");
                stack.push(t);
                stack.push(t.right);
                stack.push(t.left);
            }else{
                rr.add(t.val);
            }
        }
        return rr;
    }
}

层序遍历-从第一层到最后一层

BFS加队列Queue(LinkedList)就可以,核心点就是for循环那一层的所有节点。

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> rr = new ArrayList<>();
        if(root==null){
            return rr;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            int nowSize = queue.size();
            List<Integer> rr2 = new ArrayList<>();
            for(int i = 0 ;i<nowSize;i++){
                TreeNode t = queue.poll();
                rr2.add(t.val);
                if(t.left!=null){
                    queue.add(t.left);
                }
                if(t.right!=null){
                    queue.add(t.right);
                }  
            }
            rr.add(new ArrayList<>(rr2));
        }
        return rr;
    }
}

层序遍历-从最后一层到第一层

把上面的结果反着输出就好了

class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> rr = new ArrayList<>();
        List<List<Integer>> rr3 = new ArrayList<>();

        if(root==null){
            return rr;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            int nowSize = queue.size();
            List<Integer> rr2 = new ArrayList<>();
            for(int i = 0 ;i<nowSize;i++){
                TreeNode t = queue.poll();
                rr2.add(t.val);
                if(t.left!=null){
                    queue.add(t.left);
                }
                if(t.right!=null){
                    queue.add(t.right);
                }  
            }
            rr.add(new ArrayList<>(rr2));
        }
        for(int i=rr.size()-1;i>=0;i--){
            rr3.add(rr.get(i));
        }
        return rr3;
    }
}

二叉树的最小深度

关键是搞清楚递归结束条件

叶子节点的定义是左孩子和右孩子都为 null 时叫做叶子节点
当 root 节点为空时,返回 0
当 root 节点左右孩子都为空时,返回 1 这是叶子节点
当 root 节点左右孩子有一个为空时,返回不为空的孩子节点的深度 因为没有到叶子节点还得继续往下走。
当 root 节点左右孩子都不为空时,返回左右孩子较小深度的节点值

class Solution {
    public int minDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        if(root.left==null||root.right==null){
            return Math.max(minDepth(root.left),minDepth(root.right))+1;
        }
        if(root.left==null&&root.right==null){
            return 1;
        }
        return  Math.min(minDepth(root.left),minDepth(root.right))+1;
    }
}

判断它是否是高度平衡的二叉树。

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
思路是对二叉树做先序遍历,从底至顶返回子树最大高度,若判定某子树不是平衡树则 “剪枝” ,直接向上返回。

算法流程:
recur(root):

递归返回值:
当节点 root 左 / 右子树的高度差 < 2 ;则返回以节点 root 为根节点的子树的最大高度,即节点 root 的左右子树中最大高度加 1( max(left, right) + 1 );
当节点 root 左 / 右子树的高度差 ≥2 :则返回 −1 ,代表 此子树不是平衡树 。
递归终止条件:
当越过叶子节点时,返回高度 0;
当左(右)子树高度 height== -1 时,代表此子树的 左(右)子树 不是平衡树,因此直接返回 −1 ;
isBalanced(root) :
返回值: 若 recur(root) != -1 ,则说明此树平衡,返回 true ; 否则返回 false 。

先看这个代码

class Solution {
    public boolean isBalanced(TreeNode root) {
        return dfs(root)[0] == 1;
    }

    private int[] dfs(TreeNode root){
        if(root == null)return new int[]{1, 0};
        int[] result = new int[2];// result[0]表示当前节点受否符合二叉树,1为true,0为false;result[1]表示当前节点的高度

        int[] left = dfs(root.left);// 递归计算左子树
        int[] right = dfs(root.right);// 递归计算右子树

        result[1] = Math.max(left[1], right[1]) + 1;// 当前节点高度

        int minus = Math.abs(left[1] - right[1]);// 左右子树的高度差的绝对值

        result[0] = left[0] & right[0] & (minus < 2 ? 1 : 0);
        return result;
    }
}

优化后

class Solution {
    public boolean isBalanced(TreeNode root) {
        return getHeight(root) != -1;
    }
//返回节点node的最大深度。
    public int getHeight(TreeNode node){
        if (node == null) {
            return 0;
        }
        int leftH = getHeight(node.left);
        if(leftH == -1) return -1;
        int rightH = getHeight(node.right);
        if(rightH == -1) return -1;
        return Math.abs(leftH-rightH)>=2?-1:Math.max(leftH,rightH)+1;
    }
}

相关文章

  • goLang 二叉树遍历(递归 非递归 前序遍历 中序遍历 后序

    goLang 二叉树遍历(递归 非递归 前序遍历 中序遍历 后序遍历 层序遍历) 前序遍历 中序遍历 后序遍历 代...

  • 二叉树的遍历方式

    二叉树的遍历方式有多种,前序遍历,中序遍历,后序遍历,层序遍历,在这里来介绍一下前、中、后序遍历。 前序遍历:根左...

  • 二叉树的遍历与创建

    二叉树的遍历 分为:前序,中序,后序,层序。 前/中/后序,是根据跟节点遍历的前后顺序来定义的。 前序遍历 从根节...

  • ALI 算法

    二叉树遍历算法: 按层遍历, 中序前序后序:

  • 二叉树遍历算法

    二叉树遍历算法有4种,先序、中序、后序和层序遍历 先序遍历:先根、后左、再右中序遍历:先左、后根、再右后序遍历:先...

  • 二叉树BinaryTree

    Java 实现二叉树的构造以及遍历过程 二叉树遍历(先序、中序、后序)

  • 二叉树的遍历

    二叉树的遍历 二叉树常用的遍历方式有:前序遍历、中序遍历、后序遍历、层序遍历四种遍历方式,不同的遍历算法,其思想略...

  • leetcode 144 145 94

    二叉树遍历 前序遍历 中序遍历 后序遍历

  • 二叉树遍历-JAVA实现

    基础二叉树 二叉树遍历分为前序、中序、后序递归和非递归遍历、还有层序遍历。 前序递归遍历算法:访问根结点-->递归...

  • 数据结构与算法之二叉树遍历(七)

    目录 前序遍历中序遍历后序遍历层序遍历遍历方式的选择条件根据遍历结果重构二叉树翻转二叉树计算二叉树的高度判断一棵树...

网友评论

      本文标题:二叉树的前,中,后序遍历,以及层序遍历。

      本文链接:https://www.haomeiwen.com/subject/vetljdtx.html