【Java数据结构】二叉树详解(四)

🔒文章目录:

1.❤️❤️前言~🥳🎉🎉🎉

2.给定一个二叉树, 找到该树中两个指定节点的最近公共祖先 

2.1第一种思路 

2.2第二种思路  

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

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

5.二叉树创建字符串

6.二叉树非递归实现前序遍历

 7.二叉树非递归实现中序遍历

8.二叉树非递归实现后序遍历

9.总结


1.❤️❤️前言~🥳🎉🎉🎉

Hello, Hello~ 亲爱的朋友们👋👋,这里是E绵绵呀✍️✍️。

如果你喜欢这篇文章,请别吝啬你的点赞❤️❤️和收藏📖📖。如果你对我的内容感兴趣,记得关注我👀👀以便不错过每一篇精彩。

当然,如果在阅读中发现任何问题或疑问,我非常欢迎你在评论区留言指正🗨️🗨️。让我们共同努力,一起进步!

加油,一起CHIN UP!💪💪

🔗个人主页:E绵绵的博客
📚所属专栏:

1. JAVA知识点专栏

        深入探索JAVA的核心概念与技术细节

2.JAVA题目练习

        实战演练,巩固JAVA编程技能

3.c语言知识点专栏

        揭示c语言的底层逻辑与高级特性

4.c语言题目练习

        挑战自我,提升c语言编程能力

📘 持续更新中,敬请期待❤️❤️

2.给定一个二叉树, 找到该树中两个指定节点的最近公共祖先 

 📌题目描述 

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)” 


2.1第一种思路 

📋题目思路 

  1. 首先,检查根节点是否为null,如果是,则返回null。这是递归算法的基本情况之一,用于处理空树的情况。

  2. 接下来,检查根节点是否等于其中一个指定节点,如果是,则返回根节点。这是另一个基本情况,处理了当根节点就是目标节点之一的情况。

  3. 然后,分别递归地在左子树和右子树中寻找指定节点的最近公共祖先,并将结果存储在left和right变量中。

  4. 如果左右子树中都找到了指定节点,则说明当前根节点就是这两个节点的最近公共祖先,返回当前根节点。

  5. 如果只有一个子树找到了指定节点,那么这个子树的返回值就是这两个节点的最近公共祖先,返回该子树的返回值。

  6. 如果左右子树都没有找到指定节点,则返回null。

这个算法是一个递归算法,通过深度优先搜索遍历整个树从而查找最近公共祖先。

⏳题目代码  

 // 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
            public BTNode lowestCommonAncestor(BTNode root, BTNode p, BTNode q) {
                      if(root==null)
                          return null;
                      if(root==p||root==q)
                          return  root;
                      BTNode left=lowestCommonAncestor(root.left,p,q);
                      BTNode right=lowestCommonAncestor(root.right,p,q);
                      if(left!=null&&right!=null)
                          return  root;
                      if(left==null&&right!=null)
                          return  right;
                      if(left!=null&&right==null)
                          return  left;
                      if(left==null&&right==null)
                          return  null;

                      return  null;
            }

2.2第二种思路  

📋题目思路  

  1. 首先定义了一个lowestCommonAncestor方法,接收三个参数:根节点root,和两个指定节点pq

  2. 创建了两个Stack对象,stack1stack2,用于分别存储从根节点到指定节点pq的路径。

  3. 调用getStack方法分别获取从根节点到pq的路径,并将路径存储在stack1stack2中。

  4. 如果两条路径都成功获取,则进入后续处理。

  5. 获取到路径后,计算两个栈的大小,并确保它们在最后一个共同节点处相等。如果不相等,则将较长的栈中的节点出栈,直到两个栈的大小相等为止。

  6. 然后,同时从两个栈中弹出元素,直到找到最后一个相同的节点。这个节点就是最近的公共祖先。

  7. 如果没有找到共同节点,返回null。

  8. getStack方法中,也是一个递归方法,用于获取从根节点到指定节点的路径。它接收一个栈对象、根节点和目标节点作为参数。

  9. 如果根节点为null,返回false。

  10. 将当前节点加入栈中。

  11. 如果当前节点是目标节点,则返回true。

  12. 否则,递归地在左子树和右子树中查找目标节点。如果找到目标节点,则直接退出该方法且返回true。否则将栈顶元素弹出,并返回false。

我们这第二种思路利用栈和递归去解决问题的,比第一种思路要相对复杂点。

 ⏳题目代码  

   public BTNode lowestCommonAncestor(BTNode root, BTNode p, BTNode q) {
        Stack<BTNode> stack1=new Stack<>();
        Stack<BTNode> stack2=new Stack<>();
         if (getStack(stack1,root,p)&&getStack(stack2,root,q)){
             int a= stack1.size();
             int b= stack2.size();
            while(a!=b){
                if(a>b) {
                    stack1.pop();
                    a--;
                }
                else{
                    stack2.pop();
                    b--;
            }}
            while(!stack1.isEmpty()){
                if(stack1.peek()==stack2.peek())
                    return  stack1.peek();
                else
                    stack1.pop();
                    stack2.pop();
            }
                 return  null;
         }

         return  null;
    }

     public boolean getStack(Stack<BTNode> stack,BTNode root,BTNode p){
                  if(root==null)
                    return false;
              stack.push(root);
                 if (root==p)
                  return true;
              if(!(getStack(stack,root.left,p)||getStack(stack,root.right,p))) {
                  stack.pop();
                  return false;
              }
              return true;
     }

该题链接:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先 


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

 📌题目描述 

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。


 📋题目思路 

我们需要实现一个构建二叉树的方法 buildTree,根据给定的先序遍历数组 preorder 和中序遍历数组 inorder,返回构建的二叉树的根节点。其中,通过静态内部类 TreeNode 来表示二叉树的每个节点,每个节点有一个值 value 和两个指向左右子树的 left、right 指针。

具体实现思路是:先序遍历数组 preorder 的第一个元素为当前根节点,然后在中序遍历数组 inorder 中找到该根节点的位置,从而确定左右子树的范围。而后通过递归方式依次构建左右子树,并返回当前节点,最终返回整棵二叉树的根节点。

其中,我们还要有getIndex 方法用于在中序遍历数组中查找指定值的位置,还需要通过设置成员变量i去遍历先序数组中的元素。

 ⏳题目代码 

//给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,
// 请构造二叉树并返回其根节点。
public class Test3 {
    public int i;

    static class TreeNode {
        int value;
        TreeNode left;
        TreeNode right;

        public TreeNode(int value) {
            this.value = value;
        }
    }

    public TreeNode buildTree(int[] preorder, int[] inorder) {
         return    build(preorder,inorder,0,inorder.length-1);
    }

    public int getIndex(int[] inorder,int value,int began,int end){
        for (int j = began; j <=end ; j++) {
            if(inorder[j]==value)
                return  j;
        }
        return  -1;
    }
    public  TreeNode  build(int[] preorder,int[] inorder,int began,int end) {
        if(began>end)
            return  null;
        TreeNode treeNode = new TreeNode(preorder[i]);
        int index = getIndex(inorder, preorder[i], began,end);
        i++;
        treeNode.left = build(preorder,inorder,began,index-1);
        treeNode.right=build(preorder,inorder,index+1,end);
        return  treeNode;
    }


}

该题链接:根据一棵树的前序遍历与中序遍历构造二叉树 


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

 📌题目描述 

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。


 📋题目思路  

跟我们上一题思路差不多

我们需要实现一个构建二叉树的方法 buildTree,根据给定的后序遍历数组 postorder 和中序遍历数组 inorder,返回构建的二叉树的根节点。其中,通过静态内部类 TreeNode 来表示二叉树的每个节点,每个节点有一个值 value 和两个指向左右子树的 left、right 指针。

具体实现思路是:后序遍历数组 postorder 的最后一个元素为当前根节点,然后在中序遍历数组 inorder 中找到该根节点的位置,从而确定左右子树的范围。而后通过递归方式依次构建左右子树,并返回当前节点,最终返回整棵二叉树的根节点。

 ⏳题目代码 

//给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,
// 请你构造并返回这颗 二叉树 。
public class Test4 {
    public int i;

    static class TreeNode {
        int value;
       TreeNode left;
       TreeNode right;

        public TreeNode(int value) {
            this.value = value;
        }
    }
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        i=postorder.length-1;
        return    build(postorder,inorder,0,inorder.length-1);
    }

    public int getIndex(int[] inorder,int value,int began,int end){
        for (int j = began; j <=end ; j++) {
            if(inorder[j]==value)
                return  j;
        }
        return  -1;
    }
    public TreeNode build(int[] preorder, int[] inorder, int began, int end) {
        if(began>end)
            return  null;
        TreeNode treeNode = new TreeNode(preorder[i]);
        int index = getIndex(inorder, preorder[i], began,end);
        i--;
        treeNode.right = build(preorder,inorder,index+1,end);
        treeNode.left=build(preorder,inorder,began,index-1);
        return  treeNode;
    }


}

 该题链接:根据一棵树的中序遍历与后序遍历构造二叉树 


5.二叉树创建字符串

📌题目描述 

给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。

空节点使用一对空括号对 "()" 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。


  📋题目思路  

  1. 定义了一个Solution1类,其中包含了一个静态内部类TreeNode,用于表示二叉树的节点。

  2. tree2str方法是转换函数的入口,接收一个根节点root,返回转换后的字符串。

  3. 创建了一个StringBuilder对象stringBuilder,用于拼接转换后的字符串。

  4. 如果根节点为null,直接返回空字符串。

  5. 将根节点的值添加到stringBuilder中。

  6. 调用getString方法来递归构建字符串。

  7. getString方法是递归构建字符串的核心方法,接收一个StringBuilder对象和当前节点作为参数。

  8. 如果当前节点的左右子节点都为空,说明当前节点是叶子节点,直接返回。

  9. 根据当前节点的左右子节点情况,按照题目要求构建字符串:

    • 如果左子节点为空而右子节点不为空,则添加"()"和右子节点的值。
    • 如果右子节点为空而左子节点不为空,则添加左子节点的值。
    • 如果左右子节点都不为空,则添加左子节点的值和右子节点的值。
  10. 继续递归调用getString方法处理左右子节点。

  11. 最后返回构建好的字符串。

 ⏳题目代码 

//给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。
class Solution1 {
    static class TreeNode {
        int value;
        TreeNode left;
        TreeNode right;

        public  TreeNode(int value) {
            this.value = value;
        }
    }
    public String tree2str(TreeNode root) {
        StringBuilder stringBuilder=new StringBuilder();
              if(root==null)
            return  stringBuilder.toString();
            stringBuilder.append(root.value);
           getString (stringBuilder,root);
          return   stringBuilder.toString();
    }
    public void getString(StringBuilder stringBuilder,TreeNode root){
        if(root.left==null&&root.right==null)
            return  ;

            if(root.left==null&&root.right!=null) {
                stringBuilder.append("()");
                stringBuilder.append("(");
                stringBuilder.append(root.right.value);
                getString(stringBuilder,root.right);
                stringBuilder.append(")");
            }
            if(root.left!=null&&root.right==null){
                stringBuilder.append("(");
                stringBuilder.append(root.left.value);
                getString(stringBuilder,root.left);
                stringBuilder.append(")");
            }
            if(root.left!=null&&root.right!=null){
                stringBuilder.append("(");
                stringBuilder.append(root.left.value);
                getString(stringBuilder,root.left);
                stringBuilder.append(")");
                stringBuilder.append("(");
                stringBuilder.append(root.right.value);
                getString(stringBuilder,root.right);
                stringBuilder.append(")");
            }
    }


}

该题链接:二叉树创建字符串 


6.二叉树非递归实现前序遍历

📌题目描述 

用非递归的方式(循环方式)实现前序遍历

 📋题目思路  

  1. 定义了一个preorderTraversal方法,接收一个根节点root,返回树的前序遍历结果。

  2. 创建了一个ArrayList对象list,用于存储遍历结果。

  3. 创建了一个Stack对象stack,用于辅助遍历。

  4. 如果根节点为null,直接返回空的遍历结果列表。

  5. 进入循环,直到根节点为null并且栈为空为止。

  6. 内部循环:在每次循环中,将当前节点的值加入到遍历结果列表中,并将当前节点入栈。然后,沿着左子树一直向下遍历,直到遇到没有左子节点的节点为止。

  7. 一旦当前节点的左子树遍历完成,将当前节点出栈,并将当前节点指向其右子节点。

  8. 重复步骤6和7,直到遍历完成。

  9. 返回遍历结果列表。

 ⏳题目代码

   public List<Integer> preorderTraversal(BTNode root) {
                  List<Integer> list=new ArrayList<>();
                      Stack<BTNode> stack=new Stack<>();
                      if(root==null)
                          return list;
                      while(root!=null||!stack.isEmpty()){
                       while(root!=null){
                        list.add(root.value);
                        stack.push(root);
                        root=root.left;
                    }
                  root= stack.pop().right;
           }
                      return list;
        }

 该题链接:二叉树非递归实现前序遍历


 7.二叉树非递归实现中序遍历

📌题目描述 

用非递归的方式(循环方式)实现中序遍历

  📋题目思路  

  1. 定义了一个inorderTraversal方法,接收一个根节点root,返回树的中序遍历结果。

  2. 创建了一个ArrayList对象list,用于存储遍历结果。

  3. 创建了一个Stack对象stack,用于辅助遍历。

  4. 如果根节点为null,直接返回空的遍历结果列表。

  5. 进入循环,直到根节点为null并且栈为空为止。

  6. 内部循环:在每次循环中,将当前节点的所有左子节点入栈,直到当前节点为空。

  7. 出栈一个节点,并将其右子节点作为当前节点。

  8. 将出栈节点的值添加到遍历结果列表中。

  9. 重复步骤6到8,直到遍历完成。

  10. 返回遍历结果列表。

  ⏳题目代码

public List<Integer> inorderTraversal(BTNode root) {
        List<Integer> list=new ArrayList<>();
        Stack<BTNode> stack=new Stack<>();
          if(root==null)
              return list;
          while(root!=null||!stack.isEmpty()){
              while (root!=null){
                  stack.push(root);
                  root=root.left;
              }
               BTNode btNode=stack.pop();
              root=btNode.right;
              list.add(btNode.value);
          }
          return list;
    }

该题链接 :二叉树非递归实现中序遍历


8.二叉树非递归实现后序遍历

📌题目描述 

用非递归的方式(循环方式)实现后序遍历

 📋题目思路  

  1. 定义了一个postorderTraversal方法,接收一个根节点root,返回树的后序遍历结果。

  2. 创建了一个ArrayList对象list,用于存储遍历结果。

  3. 创建了一个Stack对象stack,用于辅助遍历。

  4. 如果根节点为null,直接返回空的遍历结果列表。

  5. 进入循环,直到根节点为null并且栈为空为止。

  6. 内部循环:在每次循环中,将当前节点的所有左子节点入栈,直到当前节点为空。

  7. 在每次内部循环结束后,通过stack.peek()获取当前栈顶节点,将其赋值给btNode

  8. 定义prev节点,初始化为当前栈顶节点。

  9. root指向btNode的右子节点。

  10. 如果root为null,说明当前节点的左右子树已经遍历完毕,将当前节点的值加入到遍历结果列表中,并将栈顶节点出栈。

  11. 检查栈是否为空,如果为空,则遍历结束,返回结果列表。

  12. 如果栈不为空,则将root重新指向栈顶节点的右子节点,然后从栈中取出节点,直到当前root节点与prev节点的右子节点不相等为止,将取出的节点加入到结果列表中。

  13. 重复步骤6到12,直到遍历完成。

  14. 返回遍历结果列表。

 ⏳题目代码

   public List<Integer> postorderTraversal(BTNode root) {
        List<Integer> list=new ArrayList<>();
        Stack<BTNode> stack=new Stack<>();
          if(root==null)
              return list;
          while (root!=null||!stack.isEmpty()){
              while(root!=null){
                  stack.push(root);
                  root=root.left;
              }
            BTNode btNode= stack.peek();
              BTNode prev=btNode;
              root=btNode.right;

              if(root==null){
                 list.add(stack.pop().value);
                 if (stack.isEmpty())
                     return list;
                 root=stack.peek().right;
                 while (root==prev){
                     prev=stack.pop();
                 list.add(prev.value);
                   if(stack.isEmpty())
                       return  list;
                 root=stack.peek().right;
                 }
          }}
          return  list;
    }


}

该题链接:二叉树非递归实现后序遍历 

9.总结 

所以我们这一篇文章就把二叉树的相关习题全讲解完了,二叉树这一章节也就全部结束了。下篇文章将会给大家带来 优先级队列(堆)的讲解。在此,我们诚挚地邀请各位大佬们为我们点赞、关注,并在评论区留下您宝贵的意见与建议。让我们共同学习,共同进步,为知识的海洋增添更多宝贵的财富!🎉🎉🎉❤️❤️💕💕🥳👏👏👏

  • 37
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值