【Java数据结构】二叉树进阶——非递归实现前中后序遍历二叉树+进阶大厂面试题
🗽非递归实现遍历二叉树(深入理解二叉树)
⭐非递归前序遍历
⭐非递归中序遍历
⭐非递归后序遍历
🗽大厂OJ面试题
🎄1. 二叉树的构建及遍历
🎄2. 二叉树的分层遍历
🎄3. 给定一个二叉树,找到该树中两个指定节点的最近公共祖先
🎄4. 二叉树搜索树转换成排序双向链表
🎄5. 根据一棵树的前序遍历与中序遍历构造二叉树
🎄6. 根据一棵树的中序遍历和后序遍历构造二叉树
🎄7. 二叉树创建字符串
代码每行都有注释,可以一步一步的画着图走一走,多走几遍,理解会上一个档次!
前序遍历和中序遍历都用到栈,代码可以说一模一样,只不过打印节点的时机不一样
题目:
思路:
- 本题思路很简单,就是遍历字符串,因为这是根据前序遍历搞出来的字符串
- 所以构建二叉树,也要根据这个 根->左节点->右节点 的顺序来构建
实现代码:
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);
}
}
- 层序遍历就是一层一层的遍历节点
这题还有一个要求就是,输出的时候将一层的节点放在一行,下一层的节点放在下一行,这就需要用到一个
二维数组
来储存
每一层的节点
我们先来观察一下 层序遍历的过程中,结点进队列和出队列的过程: 请看图
可是如何知道当前访问到的节点是哪一层的呢? 截取 BFS 遍历过程中的某个时刻:
可以看到,此时队列中的结点是 3、4、5,分别来自第 1 层和第 2 层。这个时候,第 1 层的结点还没出完,第 2 层的结点就进来了,而且两层的结点在队列中紧挨在一起,我们无法区分队列中的结点来自哪一层。
因此,我们在每一层遍历开始前,先记录队列中的结点数量 n(也就是这一层的结点数量),然后一口气处理完这一层的 n 个结点
祖先的定义: 若节点 p 在节点 root 的左(右)子树中,或 p = root ,则称 root 是 p 的祖先。
根据以上定义,若 root 是 p,q 的 最近公共祖先 ,则只可能为以下情况之一:
①p 和 q 在 root的子树中,且分列 root 的 异侧(即分别在左、右子树中);
②p = root ,且 q 在 root 的左或右子树中;
③q = root ,且 p 在 root 的左或右子树中;
考虑通过递归对二叉树进行先序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当节点 p,q 在节点 root的异侧时,节点 root 即为最近公共祖先,则向上返回 root 。
- 已知将二叉搜索树进行中序遍历可以得到
,因此本题最直接的想法就是由小到大的顺序排列
。进行中序遍历
- 根据题目的要求1,不能创建新的结点,所以我们
设置一个pre用于指向前驱节点
- 所以我们只需要根据先序遍历得到根节点,然后在中序遍历中找到根节点的位置,它的左边就是左子树的节点,右边就是右子树的节点。
递归生成左子树和右子树
- 和上题几乎一样,只需要
几处小改动
- 因为是给的是
,所以构建的时候,后续遍历
,并且构建的时候是读取后续遍历数组要从后往前读取
根->右->左
-
我们可以使用递归的方法得到二叉树的前序遍历。在递归时,根据题目描述,我们需要加上额外的括号,会有以下 4 种情况:
① 如果
,那我们在递归时,需要在当前节点有两个孩子
②如果两个孩子的结果外都加上一层括号;
,那我们当前节点没有孩子
;不需要在节点后面加上任何括号
- 如果
,那我们在递归时,只需要在当前节点只有左孩子
左孩子的结果外加上一层括号,而不需要给右孩子加上任何括号
④如果
当前节点只有右孩子
,那我们在递归时,需要
先加上一层空的括号 () 表示左孩子为空
,再对右孩子进行递归,
并在结果外加上
考虑完上面的 4 种情况,我们就可以得到最终的字符串。