代码改变世界

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

2025-12-02 11:22  tlnshuju  阅读(0)  评论(0)    收藏  举报


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

1. 前言

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


2. 正文

1. 二叉树的练习题

  1. 检查两棵树是否为相同的树,首先判断是否为相同的树需要两点,
    (1)结构相同
    (2)节点具有相同的值
    在这里插入图片描述根据图上的思路我们的代码很简单就完成了
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,
    不相同再判断左子树与子树是否相同,采用递归的思想
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. 翻转二叉树
    在这里插入图片描述对于这个操作的实现还是很简单的
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是否为对称的方法
    在这里插入图片描述
    之后我们直接调用这个方法,就可以完成代码
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 ,注意是每一个结点
    ****在上篇博客的学习中,我们已经学会了如何求树的高度
    在这里插入图片描述我们只需要在这个基础上完善代码即可
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,这个代码就有问题了!!

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方法也可以这样写

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走到最左边!下面我们完善代码

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修饰但是调用方法时要用类的引用调用。

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. 二叉树的层序遍历,题目中出现了我们之前遇到的二维数组,我们要以二维数组的方式进行输出,其中每一行的一维数组代表二叉树的各个元素,在完成这道题之前,我们先来看看普通的层序遍历应该如何去做呢?
    对于层序遍历,我们可以不使用递归来实现,我们需要引入队列这个数据结构去实现我们的操作
    在这里插入图片描述
    我们可以根据图完成代码
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);
  }
  }
  }

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

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

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,这样我们的代码就完成了
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. 结语

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