【JAVA】数据结构——二叉树 例题练习及代码详解

目录

1.判断两个二叉树是否相同:节点数值相同,结构都相同

2.判断其中一棵树是否为另一棵树的子树

3.判断是否是平衡二叉树

4.判断二叉树是否是平衡二叉树

5.二叉树的创建及遍历: 给定一个带空格的前序二叉树序列 ,求它的 输出中序、后序遍历序列

6.二叉树的层序遍历:给二叉树的根节点 root ,返回其节点值的 层序遍历

7.二叉树p,q节点的 最近 公共 祖先LCA

8.二叉搜索树与双向链表:输入一棵二叉搜索树,将该二叉搜索树转换成一个 排序的 双向链表

9.从前序与中序遍历序列构造二叉树:  preorder 和 inorder ,构造二叉树并返回其根节点。

10. 从中序与后序遍历序列构造二叉树: inorder 和 postorder,构造并返回二叉树

11. 根据二叉树创建字符串:二叉树的根节点root,采用前序遍历 的方式:


1.判断两个二叉树是否相同:节点数值相同,结构都相同

    public boolean isSameTree(TreeNode p, TreeNode q) {
        if ((p == null && q != null) || (p != null && q == null)) return false;
        if (p == null && q == null) return true;
        if (p.val != q.val) {
            return false;
        }
        //两个数的val相同
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }

2.判断其中一棵树是否为另一棵树的子树

    //另一棵树的子树:给定两个二叉树,判断其中一个数subroot是否是另一棵树root的子树
    //首先判断两棵树是否都存在是否都为空,若两棵树相同也属于子树
    //判断对应的左右子树是否是相同的
    // 时间复杂度:O(m*n)
    public boolean isSubTree(TreeNode root, TreeNode subroot) {
        //只要有一个数为空就不符合子树条件
        if (root == null || subroot == null) return false;
        if (isSameTree(root, subroot)) {
            return true;  //判断两棵树是否相同
        }
        if (isSubTree(root.left, subroot)) {
            return true; //判断subroot是否是左子树
        }
        if (isSubTree(root.right, subroot)) {
            return true; //判断subroot是否是右边子树
        }
        return false;
    }

3.判断是否是平衡二叉树

    //给定一个二叉树,判断它是否是高度平衡的二叉树。-->/平衡二叉树的子树也是平衡二叉树
    //解析:1.root左树高度-右树高度《=1;
    //2.root的左树是平衡点,右树也是平衡点   

 public int height(TreeNode root) {
        if (root == null) return 0;
        int leftheight = height(root.left);
        int rightheight = height(root.right);

        if (leftheight >= 0 && rightheight >= 0 &&Math.abs(leftheight - rightheight) <= 1) {
            return Math.max(leftheight,rightheight) +1;
        }else {
            return -1;
        }
    }
//时间复杂度O(N)
    public boolean isBalanced(TreeNode root) {
        if (root == null) return true;
        return height(root) >= 0;
    }

4.判断二叉树是否是平衡二叉树

//给你一个二叉树的根节点 root , 检查它是否轴对称--->
//解析:1.查看左树和右树是否对称:左树的左子树和右边树的右子树相同
    //2.
    public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {
        if (leftTree != null && rightTree ==null) return false;
        if (leftTree == null && rightTree !=null) return false;
        if (leftTree == null && rightTree ==null) return true;

        if (leftTree.val != rightTree.val) return false;
        return isSymmetricChild(leftTree.left,rightTree.right) &&
                isSymmetricChild(leftTree.right,rightTree.left);
    }

    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        return isSymmetricChild(root.left,root.right);
    }

5.二叉树的创建及遍历: 给定一个带空格的前序二叉树序列 ,求它的 输出中序、后序遍历序列

//  二叉树的创建及遍历 给定一个带空格的前序二叉树序列 ,求它的   输出中序、后序遍历序列      --->
//解析:1.前序遍历可以确定根节点,

    public static void inorder(TreeNode root) {
        if (root == null)  return;
        inorder(root.left);
        System.out.print(root.val+" ");
        inorder(root.right);
    }

    public static int i = 0;
    public static TreeNode createTree(String str) {

        TreeNode root = null;
        if (str.charAt(i) != '#') {
            root = new TreeNode(str.charAt(i)); //当前不是#即为根节点
            i++;
            root.left = createTree(str);
            root.right = createTree(str);
        }else {
            i++;  //遇到#只需i++
        }
        return root;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String str = scanner.nextLine();
            TreeNode root = createTree(str);
            inorder(root);
        }
    }

6.二叉树的层序遍历:给二叉树的根节点 root ,返回其节点值的 层序遍历

// (即逐层地,从左到右访问所有节点)。-----》用队列完成
 //解析:
    public void levelOder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        if (root == null)  return ;
        queue.offer(root); //根放入队列
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            System.out.print(cur.val+" ");
            if (cur.left != null) {
                queue.offer(cur.left);
            }
            if (cur.right != null) {
                queue.offer(cur.right);
            }
        }
    }

//============层序遍历=============================================================//
//    public List<List<Integer>> levelOrder(TreeNode root) {
//        List<List<Integer>> ret = new ArrayList<>();
//        if (root == null) return ret;
//
//        Queue<TreeNode> queue1 = new LinkedList<>();
//        queue1.offer(root); //根放入队列
//
//        while (!queue1.isEmpty()) {
//            int size = queue1.size(); // size代表当前层有多少个节点
//            List<Integer> list = new ArrayList<>();
//            while (size != 0) {
//                TreeNode cur = queue1.poll();
//                list.add(cur.val);
//                if (cur.left != null) {
//                    queue1.offer(cur.left);
//                }
//                if (cur.right != null) {
//                    queue1.offer(cur.right);
//                }
//                size--;
//            }
//            ret.add(list);
//        }
//        return ret;
//    }

7.二叉树p,q节点的 最近 公共 祖先LCA

  /*孩子双亲表示法:---》链表求交点(用栈保存路径)
    1.用两个栈的存储p,q路径(如何找到根节点到指定节点路径???--》遍历:)
    2.求栈的大小
    3.让栈中多的元素出差值个元素
    4.开始出栈,直到栈顶元素相同,即此时是LCA最近公共祖先
    *
    * */
//获取路径root--》node:
    //root根节点 node指定节点,stack存储指定节点路径
    public boolean getPath(TreeNode root,TreeNode node,Stack<TreeNode> stack) {
        if (root == null || node == null) return false; //若为空节点,则无路径
        stack.push(root);
        if (root == node) return true; //若根节点为node,找到了指定节点
//如果不是根节点,则需要在左右树寻找
        boolean flg = getPath(root.left,node,stack); //左树寻找节点
        if (flg == true) {
            return true;
        }
        flg = getPath(root.right,node,stack);//右边树寻找节点
        if (flg == true) {
            return true;
        }
        stack.pop();  //左右树都没找到指定节点node,则需要弹出pop()
        return false;
    }

    public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) return null;
        Stack<TreeNode> stack1 = new Stack<>();
        getPath(root,p,stack1);//存储root到p的路径到stack1
        Stack<TreeNode> stack2 = new Stack<>();
        getPath(root,q,stack2);//存储root到q的路径到stack2

        int size1 = stack1.size();  //得到两个栈的大小
        int size2 = stack2.size();
        if (size1 > size2) {  //取两个栈差值个元素
            int size = size1-size2;
            while (size != 0) {
                stack1.pop();  //size大的栈stack1开始出元素,直至两个栈元素相同
                size--;
            }

            while (!stack1.isEmpty() && !stack2.isEmpty()) {//两个栈都不为空
                if (stack1.peek() == stack2.peek()) { //两个栈顶元素相同,则找到公共祖先
                    return stack1.pop();
                }else {
                    stack1.pop();
                    stack2.pop();
                }
            }
        }else {
            int size = size2-size1;
            while (size != 0) {
                stack2.pop(); //size大的栈stack2开始出元素,直至两个栈元素相同
                size--;
            }
            while (!stack1.isEmpty() && !stack2.isEmpty()) {
                if (stack1.peek() == stack2.peek()) {
                    return stack1.pop();
                }else {
                    stack1.pop();
                    stack2.pop();
                }
            }
        }
        return null;
    }

8.二叉搜索树与双向链表:输入一棵二叉搜索树,将该二叉搜索树转换成一个 排序的 双向链表

* 解析:1.二叉搜素树:左树<根<右树--->  中序遍历  即有序
* 2.双向链表:left做前驱prev,right后继next
* 3.操作:中序遍历过程中:修改每个节点的left,right
*
* */
    TreeNode prev = null;
    public void inorder1(TreeNode pCur) {
        if (pCur == null) return;
        inorder1(pCur.left);  //左
        pCur.left = prev;
        if (prev != null) {
            prev.right = pCur;
        }
        prev = pCur;
//        System.out.print(pCur+" ");//根
        inorder1(pCur.right);  //右
    }

    public TreeNode convert(TreeNode pRootOfTree) {
        if (pRootOfTree == null) return null;
            inorder1(pRootOfTree);

            TreeNode head = pRootOfTree;
            while (head.left != null) {
                head = head.left;
            }
            return head;
    }

9.从前序与中序遍历序列构造二叉树:  preorder 和 inorder ,构造二叉树并返回其根节点。

/*105. 从前序与中序遍历序列构造二叉树: 两个整数数组 preorder 和 inorder ,构造二叉树并返回其根节点。
 preorder 是二叉树的先序遍历(可得根节点),inorder是其中序遍历(确定左右树元素),
 *解析:1.先将Pi下标元素,创建为root
 2.中序遍历数组中找到当前下标Pi元素
 3.root.left=?
 4.root.right=?
* */
    //通过前序中序遍历创建树:前序遍历数组preorder,索引下标preindex;  中序遍历数组inorder,下标(左inbegin  右inend)
    public int preIndex = 0;
    public TreeNode1 createNewTree(int[] preorder,int[] inorder,int inbegin,int inend) {
        //满足此条件 则 说明 没有左树或者右树
        if (inbegin > inend) return null;
        //此处TreeNode为char类型,但是应该是int类型,需要在前面定义class TreeNode { public int val;}
        TreeNode1 root = new TreeNode1(preorder[preIndex]);
        //寻找前序遍历preIndex下标出的元素(preorder[preIndex])  在中序遍历  里对应的位置
        int rootindex = findIndexOfInorder(inorder,inbegin,inend,preorder[preIndex]);
        if (rootindex == -1) return null;
        preIndex++;
        root.left = createNewTree(preorder,inorder,inbegin,rootindex-1); //左右树递归
        root.right = createNewTree(preorder,inorder,rootindex+1,inend);
        return root;
    }
    //寻找其对应在中序遍历的位置::中序遍历--起始索引值--数值key
    private int findIndexOfInorder(int[] inorder,int inbegin,int inend,int key) {
        for (int i = inbegin; i <= inend; i++) {
            if (inorder[i] == key) {
                return i;
            }
        }
        return -1;
    }
    public TreeNode1 buildTree(int[] preorder,int[] inorder) {
        if (preorder == null || inorder == null) return null;
        return createNewTree(preorder,inorder,0,inorder.length-1);

    }

10. 从中序与后序遍历序列构造二叉树: inorder 和 postorder,构造并返回二叉树

    /* * 106. 从中序与后序遍历序列构造二叉树:给定两个整数数组 inorder 和 postorder
 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,构造并返回二叉树
 *解析:1.先将Pi下标元素,创建为root
 2.中序遍历数组中找到当前下标Pi元素
 3.root.right=?
 4.root.left=?
    */

    //通过前序中序遍历创建树:前序遍历数组preorder,索引下标preindex;  中序遍历数组inorder,下标(左inbegin  右inend)
    public int postIndex = 0;
    public TreeNode1 createNewTree1(int[]inorder, int[] postorder, int inbegin,int inend) {
        //满足此条件 则 说明 没有左树或者右树
        if (inbegin > inend) return null;
        //此处TreeNode为char类型,但是应该是int类型,需要在前面定义class TreeNode { public int val;}
        TreeNode1 root = new TreeNode1(postorder[postIndex]);
        //寻找前序遍历preIndex下标出的元素(preorder[preIndex])  在中序遍历  里对应的位置
        int rootindex = findIndexOfInorder1(inorder,inbegin,inend,postorder[postIndex]);
        if (rootindex == -1) return null;
        postIndex--;
        //分别创建右子树,和左子树
        //左右子树下标分别为:左边:inbegin,rootindex-1;  右边:rootindex+1,inend
        root.right = createNewTree1(inorder,postorder,rootindex+1,inend); //左右树递归
        root.left = createNewTree1(inorder,postorder,inbegin,rootindex-1);
        return root;
    }
    //寻找其对应在中序遍历的位置::中序遍历--起始索引值--数值key
    private int findIndexOfInorder1(int[] inorder,int inbegin,int inend,int key) {
        for (int i = inbegin; i <= inend; i++) {
            if (inorder[i] == key) {
                return i;
            }
        }
        return -1;
    }
    public TreeNode1 buildTree1(int[] inorder,int[] postorder) {
        if (postorder == null || inorder == null) return null;
        postIndex = postorder.length-1;
        return createNewTree1(inorder,postorder,0,inorder.length-1);
    }

11. 根据二叉树创建字符串:二叉树的根节点root,采用前序遍历 的方式:

 /*根据二叉树创建字符串:二叉树的根节点root,,采用前序遍历 的方式:
   将二叉树转化为: 一个由 括号和整数  组成的字符串,返回构造出的字符串。(空格以括号的形式输出)
  *
  */
    public void treeToString(TreeNode t,StringBuilder sb) {
        if (t == null) return;
        sb.append(t.val); //根不为空,进行拼接append

        if (t.left != null) { //t的左边不为空,拼接左括号“(”
            sb.append("(");
            treeToString(t.left,sb); //继续递归操作,查找每一个左树
            sb.append(")");//左树走完,拼接append右括号“)”
        }else {  //左树为空的情况下,考虑左子树的右树
            if (t.right ==null) {
                return;
            }else {
                sb.append("()");
            }
        }
        //考虑右树的情况
        if(t.right ==null) return;
        sb.append("(");
        treeToString(t.right,sb);//执行右树递归操作
        sb.append(")");//右树树走完,拼接append右括号“)”

    }
    public String tree2str(TreeNode root) {
        if (root == null) return null;
        StringBuilder sb = new StringBuilder();  //StringBuilder用拼接操作,不会产生太多临时变量
        treeToString(root,sb);
        return sb.toString();
    }

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值