【Java数据结构】二叉树进阶——非递归实现前中后序遍历二叉树(深入理解二叉树)+进阶大厂面试题(一行一注释)

简介: 【Java数据结构】二叉树进阶——非递归实现前中后序遍历二叉树(深入理解二叉树)+进阶大厂面试题(一行一注释)

image.png

【Java数据结构】二叉树进阶——非递归实现前中后序遍历二叉树+进阶大厂面试题

🗽非递归实现遍历二叉树(深入理解二叉树)

⭐非递归前序遍历

⭐非递归中序遍历

⭐非递归后序遍历

🗽大厂OJ面试题

🎄1. 二叉树的构建及遍历

🎄2. 二叉树的分层遍历

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

🎄4. 二叉树搜索树转换成排序双向链表

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

🎄6. 根据一棵树的中序遍历和后序遍历构造二叉树

🎄7. 二叉树创建字符串

🗽非递归实现遍历二叉树(深入理解二叉树)

代码每行都有注释,可以一步一步的画着图走一走,多走几遍,理解会上一个档次!

前序遍历和中序遍历都用到栈,代码可以说一模一样,只不过打印节点的时机不一样

⭐非递归前序遍历

image.png

⭐非递归中序遍历

image.png

⭐非递归后序遍历

image.png

🗽大厂OJ面试题

🎄1. 二叉树的构建及遍历

题目:

image.png

思路:

  1. 本题思路很简单,就是遍历字符串,因为这是根据前序遍历搞出来的字符串
  2. 所以构建二叉树,也要根据这个 根->左节点->右节点 的顺序来构建

image.png

实现代码:

import java.util.*;
//题目啥也没给,节点类也要自己定义一下
class TreeNode{
    char value;//节点有值
    TreeNode left;//有左孩子节点
    TreeNode right;//有右孩子节点
    public TreeNode(char value){//构造函数,用于给节点赋值
        this.value = value;
    }
}
public class Main{
 //主函数,用于输入字符串,主要在creatTree方法里来实现
 public static void main(String[]args){
        Scanner scn = new Scanner(System.in);
        String str = scn.nextLine();
        TreeNode root =  creatTree(str);
        inOrderTraveled(root);
    }
    public static int i = 0;//i用于记录字符串中字符的下标
    //因为构建过程是递归的,不能用局部变量,所以要在外部设置成静态的
    public static TreeNode creatTree(String str){
        if(str==null){//如果字符串为空
            return null;//直接返回null
        }
        //字符串不为空,就进行构构建二叉树的过程
        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 inOrderTraveled(TreeNode root){
        if(root==null) return;
        inOrderTraveled(root.left);
        System.out.print(root.value+" ");
        inOrderTraveled(root.right);
    }
}

🎄2. 二叉树的分层遍历

题目:

image.png

思路:

  1. 层序遍历就是一层一层的遍历节点

image.png

这题还有一个要求就是,输出的时候将一层的节点放在一行,下一层的节点放在下一行,这就需要用到一个二维数组来储存每一层的节点

image.png

我们先来观察一下 层序遍历的过程中,结点进队列和出队列的过程: 请看图

image.png

可是如何知道当前访问到的节点是哪一层的呢? 截取 BFS 遍历过程中的某个时刻:

image.png

可以看到,此时队列中的结点是 3、4、5,分别来自第 1 层和第 2 层。这个时候,第 1 层的结点还没出完,第 2 层的结点就进来了,而且两层的结点在队列中紧挨在一起,我们无法区分队列中的结点来自哪一层。

因此,我们在每一层遍历开始前,先记录队列中的结点数量 n(也就是这一层的结点数量),然后一口气处理完这一层的 n 个结点

image.png

实现代码:

image.png

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

题目:

image.png

思路:


祖先的定义: 若节点 p 在节点 root 的左(右)子树中,或 p = root ,则称 root 是 p 的祖先。


根据以上定义,若 root 是 p,q 的 最近公共祖先 ,则只可能为以下情况之一:

①p 和 q 在 root的子树中,且分列 root 的 异侧(即分别在左、右子树中);

②p = root ,且 q 在 root 的左或右子树中;

③q = root ,且 p 在 root 的左或右子树中;

image.png

考虑通过递归对二叉树进行先序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当节点 p,q 在节点 root的异侧时,节点 root 即为最近公共祖先,则向上返回 root 。

image.png

实现代码:

image.png

🎄4. 二叉树搜索树转换成排序双向链表

题目:

image.png

思路:

  1. 已知将二叉搜索树进行中序遍历可以得到由小到大的顺序排列,因此本题最直接的想法就是进行中序遍历
  2. 根据题目的要求1,不能创建新的结点,所以我们设置一个pre用于指向前驱节点

image.png

实现代码:

image.png

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

题目:

image.png

思路:

  1. 所以我们只需要根据先序遍历得到根节点,然后在中序遍历中找到根节点的位置,它的左边就是左子树的节点,右边就是右子树的节点。

image.png

递归生成左子树和右子树

image.png

实现代码:

image.png

🎄6. 根据一棵树的中序遍历和后序遍历构造二叉树

题目:

image.png

思路:

  1. 和上题几乎一样,只需要几处小改动
  2. 因为是给的是后续遍历,所以构建的时候,读取后续遍历数组要从后往前读取 ,并且构建的时候是 根->右->左

实现代码:

image.png


🎄7. 二叉树创建字符串

题目:

image.png

思路:

  1. 我们可以使用递归的方法得到二叉树的前序遍历。在递归时,根据题目描述,我们需要加上额外的括号,会有以下 4 种情况:
    ① 如果当前节点有两个孩子,那我们在递归时,需要在两个孩子的结果外都加上一层括号;
    ②如果当前节点没有孩子,那我们不需要在节点后面加上任何括号
  2. image.png
  3. 如果当前节点只有左孩子,那我们在递归时,只需要在左孩子的结果外加上一层括号,而不需要给右孩子加上任何括号

image.png

④如果当前节点只有右孩子,那我们在递归时,需要先加上一层空的括号 () 表示左孩子为空,再对右孩子进行递归,并在结果外加上

image.png

考虑完上面的 4 种情况,我们就可以得到最终的字符串。

实现代码:

image.png









相关文章
|
4天前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
32 8
|
2天前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
|
13天前
|
Java 程序员 编译器
Java|如何正确地在遍历 List 时删除元素
从源码分析如何正确地在遍历 List 时删除元素。为什么有的写法会导致异常,而另一些不会。
15 3
|
26天前
|
前端开发 小程序 Java
java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机
这篇文章介绍了Java中Map的遍历方法、使用Pattern和matches进行正则表达式匹配,以及后端向前端传输图片并保存到手机的三种情况。
17 1
|
27天前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
16 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
27天前
|
存储 算法 搜索推荐
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
这篇文章主要介绍了顺序存储二叉树和线索化二叉树的概念、特点、实现方式以及应用场景。
17 0
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
|
27天前
|
存储 算法
探索数据结构:分支的世界之二叉树与堆
探索数据结构:分支的世界之二叉树与堆
|
11天前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
88 38
|
8天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
3天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####