数据结构之**二叉树**超全秘籍宝典2

文章目录

  • [*1. 前言*](#1. 前言)
  • [*2. 正文*](#2. 正文)
      • [1. 二叉树的练习题](#1. 二叉树的练习题)
  • [*3. 结语*](#3. 结语)

"你的每一分耕耘,都藏着未来的收获与惊喜"

1. 前言

本文主要围绕链式二叉树的习题展开,请大家跟进小编的步伐!! 🌹🌹🌹


2. 正文

1. 二叉树的练习题

  1. 检查两棵树是否为相同的树,首先判断是否为相同的树需要两点,
    (1)结构相同
    (2)节点具有相同的值
    根据图上的思路我们的代码很简单就完成了
java 复制代码
class Solution {
     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;
        }
        return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
    }
}

这里注意一点 第二个if语句与第三个if语句的顺序不能交换!!先判断当前节点是否为空再判断值


  1. 是否为另一棵树的子树

    我们用代码来完善
    注意这里必须要讨论root==null的情况,root是在遍历树,所以会出现root为空的情况,如果root为null还没有匹配子树,那么就return false
    这里我们还需要用到第一题的方法,如果根结点与子树相同,则返回true,
    不相同再判断左子树与子树是否相同,采用递归的思想
java 复制代码
   public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if (root==null){
            return false;
        }
        if(isSameTree(root,subRoot)) return true;
        if(isSubtree(root.left,subRoot)) return true;
        if(isSubtree(root.right,subRoot)) return true;
        return false;
    }

  1. 翻转二叉树
    对于这个操作的实现还是很简单的
java 复制代码
   public TreeNode invertTree(TreeNode root) {
        if(root==null){
            return null;
        }
        TreeNode tmp=root.left;
        root.left=root.right;
        root.right=tmp;
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }

  1. 对称二叉树,判断一棵树是否为对称二叉树我们需要得知root.left 与 root.right是否为对称的

    首先我们可以先写一个专门判断二叉树的左子树leftTree与右子树rightTree是否为对称的方法

    之后我们直接调用这个方法,就可以完成代码
java 复制代码
 public boolean isSymmetric(TreeNode root) {
        if(root==null){
            return true;
        }
        return isSymmetricChild(root.left, root.right);
    }
    public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree){
        if(leftTree!=null&&rightTree==null || leftTree==null&&rightTree!=null){
            return false;
        }
        if(rightTree==null&&leftTree==null){
            return true;
        }
        if(leftTree.val!=rightTree.val){
            return false;
        }
        return isSymmetricChild(leftTree.left,rightTree.right)&&
                isSymmetricChild(leftTree.right,rightTree.left);

    }

  1. 平衡二叉树,什么是平衡二叉树?平衡二叉树是指每一个节点的左子树高度与右子树的高度的差值<=1 ,注意是每一个结点
    在上篇博客的学习中,我们已经学会了如何求树的高度
    我们只需要在这个基础上完善代码即可
java 复制代码
class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root==null){
            return true;
        }
        int leftHeight=getHeight(root.left);
        int rightHeight=getHeight(root.right);
        return Math.abs(leftHeight-rightHeight)<=1&&
                isBalanced(root.left)&&
                isBalanced(root.right);
    }
    private int getHeight(TreeNode root){
        if(root==null){
            return 0;
        }
        int leftHeight=getHeight(root.left);
        int rightHeight=getHeight(root.right);
        return Math.max(leftHeight,rightHeight)+1;
    }
}

紧贴我们的思路!!

下面我们关注一下这个代码的时间复杂度,时间复杂度为O(N^2),因为每一次求树的高度都要重新从头遍历,我们该如何让这个代码的实现达到时间复杂度为O(N)呢!? 也就是只遍历一次树即可
我们在return前增加了一串代码,如果左树右树高度之差大于1了,那么return -1,这里我们需要接收一下-1
如果左树拿到了return的值且为-1,那么我直接让左树返回-1

这里有的小伙伴就会觉得代码已经完善了,可是我们少考虑了一种情况,如果rightHeight也为负数,leftHeight==0,那么0-(-1)=1,这个代码就有问题了!!

java 复制代码
class Solution {
   public boolean isBalanced(TreeNode root) {
        if(root==null){
            return true;
        }
        return getHeight(root)>0;
    }
    private int getHeight(TreeNode root){
        if(root==null){
            return 0;
        }
        int leftHeight=getHeight(root.left);
        if(leftHeight<0){
            return -1;
        }
        int rightHeight=getHeight(root.right);
        if(Math.abs(leftHeight - rightHeight) > 1 || rightHeight<0){
            return -1;
        }else{
            return Math.max(leftHeight,rightHeight)+1;
        }
    }
}

当然这里的getHeight方法也可以这样写

java 复制代码
    private int getHeight(TreeNode root){
        if(root==null){
            return 0;
        }
        int leftHeight=getHeight(root.left);
        if(leftHeight<0){
            return -1;
        }
        int rightHeight=getHeight(root.right);
        if(Math.abs(leftHeight - rightHeight) <2&& rightHeight >= 0){
            return Math.max(leftHeight,rightHeight)+1;
        }else{
           return -1;
        }
    }

注意 "||"和"&&"区别


  1. 二叉搜索树与双向链表,这里我们的目的是输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。
    首先什么二叉搜索树?二叉搜索树就是 左子树值<根结点值<右子树值
    我们先完成中序遍历这个方法
    下面我们看如何将二叉树转换为双向链表

这样写的话,经历每一次循环root.left永远为null,可见不行!

利用一个prev的变量,将prev的right域指向循环后的root,然后让prev指向root,顺序不能变
这里还要注意prev如果为null的话就没有right域,我们再看这个代码是否有问题呢?

这里注意!!prev域不能定义在方法里,每次递归这个方法会重新给prev赋值为null

我们的要求是返回链表的头节点,这里我们传入 pRootOfTree最后它的位置仍然在根结点上,所以我们要定义一个头指针head,让head走到最左边!下面我们完善代码

java 复制代码
    public TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree == null) return null;
        ConvertChild(pRootOfTree);
        TreeNode head = pRootOfTree;
        while (head.left != null) {
            head = head.left;
        }
        return head;
    }
    private TreeNode prev=null;
    private void ConvertChild(TreeNode root) {
        if (root == null) {
            return ;
        }
        ConvertChild(root.left);
        root.left = prev;
        if (prev != null) {
            prev.right = root;
        }
        prev = root;
        ConvertChild(root.right);
    }

这样我们的代码才完善!


  1. 二叉树的构建和遍历,本题的意思是输入 ABC##DE#G##F### 其中"#"表示的是空格,空格代表空树,建立后再进行中序遍历

    我们可以先搭框架,先完成中序遍历的方式
    下面我们看看应该如何去创建这棵树

我们可以遍历传入的字符串,如果遇到非'#'那么就创造一个新的节点,i++,如果遇到'#'那么直接让i++即可
我们这里让i作为一个静态的成员变量,i 不能为局部变量,因为i的值是在改变的基础上继续变化的,当然静态的变量也有不好之处,如果传入的字符串太大则不行,所以这里可以不用static修饰但是调用方法时要用类的引用调用。

java 复制代码
 class Main {
     static class  TreeNode{
         TreeNode left;
         TreeNode right;
         char val;

         public TreeNode(char val) {
             this.val = val;
         }
     }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) {
            String str=in.nextLine();
            TreeNode root=creatTree(str);
            inOrder(root);
        }
    }
    public static int i=0;
    public static TreeNode creatTree(String str){
        TreeNode root=null;
        if(str.charAt(i)!='#'){
           root=new TreeNode(str.charAt(i));
            i++;
            root.left=creatTree(str);
            root.right=creatTree(str);
        }else{
            i++;
        }
      return root;
    }
    public static void inOrder(TreeNode root){
        if(root==null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }
}

这样这个方法就完成了


  1. 二叉树的层序遍历,题目中出现了我们之前遇到的二维数组,我们要以二维数组的方式进行输出,其中每一行的一维数组代表二叉树的各个元素,在完成这道题之前,我们先来看看普通的层序遍历应该如何去做呢?
    对于层序遍历,我们可以不使用递归来实现,我们需要引入队列这个数据结构去实现我们的操作

    我们可以根据图完成代码
java 复制代码
  public void levelOrder(TreeNode root){
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode cur=queue.poll();
            System.out.println(cur.val+" ");
            if(cur.left!=null){
                queue.offer(cur.left);
            }
            if(cur.right!=null) {
                queue.offer(cur.right);
            }
        }
    }

只要队列不为空,我就继续放,为空后我的二叉树元素就被全部打印了!

下面我们来看这道题,与上述不一样的是,我们要返回一个二维数组,下面我们思考如何结合二维数组完成二叉树的层序遍历?二维数组是由一个个一维数组组成,我们只需要把每一层元素放到一个一维数组中即可
我们直接来实现一下

java 复制代码
   public List<List<Integer>> levelOrder(TreeNode root) {
         List<List<Integer>> ret=new ArrayList<>();
        if(root==null){
            return ret;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            List<Integer> list=new ArrayList<>();
            int size=queue.size();
            while(size!=0){
            TreeNode cur=queue.poll();
             list.add(cur.val);
            if(cur.left!=null){
                queue.offer(cur.left);
            }
            if(cur.right!=null) {
                queue.offer(cur.right);
            }
            size--;
        }
          ret.add(list);
      }
      return ret;
    }

这里注意,每次的顺序表都要放在size循环中,每次cur=queue.poll()也要放入循环之中,因为如果在外就取不到值了


  1. 判断一棵树是不是完全二叉树

    我们思考什么是完全二叉树?

    这就是一个完全二叉树,我们还是利用队列来实现,那么应该如何实现呢?

    我们来完善一下代码

    首先这里与我们层序遍历二叉树很相似,我们只要碰见null就跳出循环
    跳出循环后,我们执行这部分代码,判断当前队列是否全为null,这样我们的代码就完成了
java 复制代码
   public boolean isCompleteTree(TreeNode root){
        if(root==null){
            return true;
        }
        Queue<TreeNode>queue=new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode cur=queue.poll();
            if(cur!=null){
                queue.offer(cur.left);
                queue.offer(cur.right);
            }else{
                break;
            }
        }
        while(!queue.isEmpty()){
            TreeNode peek= queue.peek();
            if (peek!=null){
                return false;
            }
            queue.poll();
        }
        return true;
    }

以上就是本篇博客的全部练习,所有代码在这🌹


3. 结语

以上就是本文主要的内容,我们主要实现了二叉树的很多练习题,接下来还会有一部分练习题,以及顺序表实现二叉树的知识,请大家敬请期待!!有不明白的地方可以留言小编会回复,希望读者们多提建议,小编会改正,共同进步!谢谢大家。🌹🌹🌹

相关推荐
Mos_x4 小时前
【Spring Boot】Spring Boot解决循环依赖
java·spring boot·spring
卡卡酷卡BUG4 小时前
2025年Java面试题及详细解答(MySQL篇)
java·开发语言·mysql
ZHE|张恒4 小时前
深入理解 Spring 原理:IOC、AOP 与事务管理
java·后端·spring
007php0074 小时前
某游戏大厂的常用面试问题解析:Netty 与 NIO
java·数据库·游戏·面试·职场和发展·性能优化·nio
北城以北88884 小时前
SSM--MyBatis框架之动态SQL
java·开发语言·数据库·sql·mybatis
迷途之人不知返5 小时前
链表相关的算法题(2)
数据结构·算法·链表
霸道流氓气质5 小时前
Java中Stream应用场景示例-订单报表分组统计
java
nju_spy5 小时前
力扣每日一题(四)线段树 + 树状数组 + 差分
数据结构·python·算法·leetcode·面试·线段树·笔试
程序员烧烤5 小时前
【Java基础14】函数式接口、lamba表达式、方法引用一网打尽(下)
java·开发语言