【数据结构】Java中二叉树常见问题代码汇总

1.二叉树前序递归与非递归遍历

递归代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class BinaryTree {     
    public void preorderTraversal(TreeNode root) {
        if(root != null) {
            System.out.println(root.val); //每次遍历都打印当前节点,然后再去打印左右子树节点,至于左右子树再怎么向下递归打印它的左右子树我们就不关心了
            preorderTraversal(root.left);  //递归调用,遍历左子树,打印左子树的节点
            preorderTraversal(root.right); //递归调用遍历右子树,打印左子树节点
        }
    }
}

非递归代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class BinaryTree {
    public void preorderTraversal(TreeNode root) {
        if(root == null) {     //空树直接返回,就不用遍历了
            return;
        }
        Stack<TreeNode> s = new Stack<>();
        s.push(root); //根节点入栈
        while(!s.empty()) {    //循环条件:栈不为空,因为栈不为空说明每遍历完
            TreeNode cur = s.pop();    //此时栈顶保存的就是根节点,由于前序遍历先打印根节点,所以先将根节点出栈,
            System.out.println(cur.val);  //打印根节点
            //由于栈先进后出特性,所以想先打印左子树节点,就将右子树节点先入栈
            if(cur.right != null) {  
                s.push(cur.right);
            } 
            if(cur.left != null) {
                s.push(cur.left);
            }
        }
    }
}

2.二叉树中序递归与非递归遍历

递归代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 class  BinaryTree {
    public void inorderTraversal(TreeNode root) {
        if(root != null) {
            inorderTraversal(root.left);    //一直递归调用到左子树为空,其实就相当于已经遍历了左子树
            System.out.println(root.val);   //所以按照次序,这里直接打印根节点
            inorderTraversal(root.right);   //然后递归调用,遍历右子树节点
        }
    }
}

非递归代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class  BinaryTree {
    public void inorderTraversal(TreeNode root) {
        if(root == null) {   //传的根节点为空直接返回,不用遍历了
            return;
        }
        Stack<TreeNode> s = new Stack<>();
        TreeNode cur = root;   //定义一个引用指向头节点,用来遍历二叉树
        while(cur!=null || !s.empty()) {  //循环条件:cur!=null 或者栈不为空时说明还没遍历完
            while(cur != null) {
                s.push(cur);       //尽可能将节点左子树依次压入栈中
                cur = cur.left;
            }
            //此时栈顶的元素是最左侧的元素,它的左子树为空,相当于左子树已经遍历了,直接将其出栈并打印
             cur = s.pop();    
             System.out.println(cur.val); 
             cur = cur.right;  //左子树与根都遍历了,此时应该遍历它右节点了
        }
    }
}

3.二叉树后序递归与非递归遍历

递归代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class  BinaryTree {
    public void postorderTraversal(TreeNode root) {
        if(root != null) {
            postorderTraversal(root.left);
            postorderTraversal(root.right);
            System.out.println(root.val);
        }
    }
}

非递归代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class  BinaryTree{
    public void postorderTraversal(TreeNode root) {
        Stack<TreeNode> s = new Stack<>();
        TreeNode cur = root;
        TreeNode lastTime = null;  //用它来记录上一次遍历的节点,后面用来和当前节点比较,看看它是不是当前节点的右子树
        while(cur != null || !s.empty()) {  //cur不为空和栈不为空都说明节点没有遍历完,需要继续循环
            while(cur != null) {
                s.push(cur);      //尽可能将节点左子树依次压入栈中
                cur = cur.left;
            }
             //此时栈顶的元素是最左侧的元素,它的左子树为空,相当于左子树已经遍历了,但是不能直接打印。
             //第一次当然很清楚是从左子树到达的根,因为它的左子树刚刚遍历完。
             //但是后面有些有些情况无法判断它是从哪到的根,所以需要判断当前节点的上一个遍历节点是不是其右子树。
            TreeNode temp = s.peek();
            //右子树为空不用遍历可以直接打印,或者刚刚从右子树回来也可以直接打印当前节点
            if(temp.right == null || temp.right == lastTime)  {
                System.out.println(temp.val);
                lastTime = temp;   //每次遍历都用lastTime保存,以便下次遍历时与节点右子树比较。
                s.pop();
            }else {
                cur = temp.right;   //右子树不为空且每遍历,就需要将右子树压栈遍历
            }
        }
    }
}

4.二叉树的层序遍历

题目链接: leetcode102 二叉树的层序遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ret = new ArrayList<>();
        if(root==null) {
            return ret;
        }
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);         //先将根节点放入队列中
        while(!q.isEmpty()) {  //队列不为空说明还没遍历完
            int size = q.size(); //size为当前层的元素个数
            List<Integer> level = new ArrayList<>(size);//用level来保存一层元素
            //一次性遍历一层的元素
            for(int i=0;i<size;i++) {
                TreeNode cur = q.poll();  //将当前层节点依次出队列
                level.add(cur.val);     //将当前层节点值放进level中
                //如果节点有左孩子,就将左孩子入队列
                if(cur.left != null) {
                    q.offer(cur.left);
                }
                //如果节点有右孩子,就将右孩子入队列
                if(cur.right != null) {
                    q.offer(cur.right);
                }
            }
            ret.add(level);   //每遍历完一层就将当前层结果放入ret中
        }
        return ret;
    }
}

5.检查两棵树是否相同

题目链接:leetcode100 两颗相同的树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if(p==null && q==null) {
            return true;
        }
        if(p==null || q==null) {
            return false;
        }
        //两棵树都不为空,就比较其节点值
        if(p.val != q.val) {
            return false;
        }
        //根节点比较之后就得继续检查他们的左右子树是否相同了
        return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
    }
}

6.检查一棵树是否为另一棵树的子树

题目链接:leetcode572 另一棵树的子树
题目描述: 给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSubtree(TreeNode s, TreeNode t) {
        //s为空树时,没有子树
        if(s == null) {
            return false;
        }
        //空树为任何非空树子树
        if(t == null) {
            return true;
        }
        //两者都不为空时则判断其是否为同一棵树
        if(isSameTree(s,t)) {
            return true;
        }
        //递归判断t是否为s的左子树或者右子树
        return isSubtree(s.left,t) || isSubtree(s.right,t);
    }
    public static boolean isSameTree(TreeNode p, TreeNode q) {
        if(p == null && q == null) {
            return true;
        }
        if(p == null || q == null) {
            return false;
        }
        if(p.val != q.val) {
            return false;
        }
        return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
    }
 }

7.求二叉树的最大深度

题目链接:leetcode104 二叉树最大深度

题目描述: 给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) {
            return 0;
        }
        return Math.max(maxDepth(root.left)+1,maxDepth(root.right)+1);
    }
}

8.判断一颗二叉树是否是平衡二叉树

题目链接: leetcode110 平衡二叉树
题目描述: 给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

解法一:自顶向下

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null) {
            return true;
        }
        if(Math.abs(height(root.left)-height(root.right)) > 1) {
            return false;
        }
        return isBalanced(root.left) && isBalanced(root.right);
    }
    private int height(TreeNode root) {
        if(root == null) {
            return 0;
        }
        return Math.max(height(root.left)+1,height(root.right)+1);
    }
}

解法二:自底向上
方法一计算 height存在大量冗余。每次调用 height时,要同时计算其子树高度。但是自底向上计算,每个子树的高度只会计算一次。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 //递归到底判断左右子树是否平衡,不平衡返回-1,平衡就返回当前节点的高度。
class Solution {
    public boolean isBalanced(TreeNode root) {
        return height(root) != -1;
    }
    private int height(TreeNode root) {
        if(root == null) {
            return  0;
        }
        int leftHeight = height(root.left);
        //如果其左子树不平衡就不用往下判断了,它肯定不平衡
        if(leftHeight == -1) {
            return -1;
        }
        int rightHeight = height(root.right);
        //如果其右子树不平衡,也直接返回-1
        if(rightHeight == -1) {
            return -1;
        }
        
        return Math.abs(rightHeight-leftHeight) < 2 ? Math.max(leftHeight,rightHeight)+1 : -1;
    }
}

9.检查一棵二叉树是否镜像对称

题目链接: leetcode101 对称二叉树
题目描述: 给定一个二叉树,检查它是否是镜像对称的。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 //可以把一棵树拆成两棵树看
class Solution {
    public boolean isSymmetric(TreeNode root) {
        return isSame(root,root);
    }
    private static boolean isSame(TreeNode a,TreeNode b) {
        if(a == null && b == null) {
            return true;
        }
        if(a == null || b == null) {
            return false;
        }
        if(a.val != b.val) {
            return false;
        }
        return isSame(a.left,b.right) && isSame(a.right,b.left);
    }
}

10.求一棵二叉树的镜像

题目链接: leetcode27 二叉树的镜像
题目描述: 请完成一个函数,输入一个二叉树,该函数输出它的镜像。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 //求镜像,即将二叉树每个节点的左右子节点交换即可
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root == null) {
            return null;
        }
        Stack<TreeNode> s = new Stack<>();
        s.push(root);
        while(!s.empty()) {
            TreeNode node = s.pop();
            if(node.left != null) {
                s.push(node.left);
            } 
            if(node.right != null) {
                s.push(node.right);
            }
            TreeNode temp = node.left;
            node.left = node.right;
            node.right = temp;
        }
        return root;
    }
}

11.根据一棵树的前序遍历与中序遍历构造二叉树

题目链接: leetcode105 从前序和中序遍历序列构建二叉树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for(int i = 0;i < inorder.length;i++) {
            if(inorder[i] == preorder[0]) {
                TreeNode root = new TreeNode(preorder[0]);
                //递归构建二叉树的左子树
                root.left = buildTree(Arrays.copyOfRange(preorder,1,i+1),Arrays.copyOfRange(inorder,0,i));
                //递归构建二叉树的右子树
                root.right = buildTree(Arrays.copyOfRange(preorder,i+1,preorder.length),Arrays.copyOfRange(inorder,i+1,inorder.length));
                //返回根节点
                return root;
            }
        }
        return null;
    }
}

12.根据一棵树的中序遍历与后序遍历构造二叉树

题目链接: leetcode106 从中序和后序遍历序列构建二叉树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        for(int i = 0; i < inorder.length; i++) {
            if(inorder[i] == postorder[postorder.length-1]) {
                TreeNode root = new TreeNode(postorder[postorder.length-1]);
                //递归构建二叉树的左子树
                root.left = buildTree(Arrays.copyOfRange(inorder,0,i),Arrays.copyOfRange(postorder,0,i));
                //递归构建二叉树的右子树
                root.right = buildTree(Arrays.copyOfRange(inorder,i+1,inorder.length),Arrays.copyOfRange(postorder,i,postorder.length-1));
                //返回根节点
                return root;
            }
        }
        return null;
    }
}

13.二叉树的最近公共祖先

题目链接: leetcode236 二叉树的最近公共祖先

题目描述: 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == p || root == q) {
            return root;
        }
        Stack<TreeNode> s = new Stack<>();
        TreeNode cur = root.left;
        //设置两个标志位,看看p,q是否都在根节点左侧
        Boolean flag1 = false;
        Boolean flag2 = false;
        while(cur != null || !s.empty()) {
            while(cur != null) {
                s.push(cur);
                cur = cur.left;
            }
            cur = s.pop();
            if(cur == p) {
                flag1 = true;
            }
            if(cur == q) {
                flag2 = true;
            }
            cur = cur.right;
        }
        //如果p,q都在左子树,就以左子树为根节点递归查找
        //如果p,q都在右子树,就以右子树为根节点递归查找
        //如果p,q在根节点两侧,那么根节点就是其最近公共祖先
        if(flag1 && flag2) {
            return lowestCommonAncestor(root.left,p,q);
        }else if(!flag1 && !flag2){
            return lowestCommonAncestor(root.right,p,q);
        }
        return root;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值