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

简介: 笔记

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


  • 代码每行都有注释,可以一步一步的画着图走一走,多走几遍,理解会上一个档次!
  • 前序遍历和中序遍历都用到栈,代码可以说一模一样,只不过打印节点的时机不一样


⭐非递归前序遍历

// 非递归实现前序遍历
    public void FDG_reOrderTraversal(TreeNode root){
        if (root == null) {//先判断根节点是否空
            return;//第一个根节点如果空的话,就直接返回了
        }
        TreeNode cur = root;//设置临时节点cur,通过这个节点来遍历整棵树
        Stack<TreeNode> stack = new Stack<TreeNode>();//创建一个栈
        while(cur != null || !stack.isEmpty()) {//外循环,先写内循环采写外循环,只要栈不为空,说明还没遍历完成
            while (cur != null) {//内循环
                stack.push(cur);//将当前cur节点入栈
                System.out.print(cur.value+" ");//打印cur节点,前序遍历是在入栈后打印
                cur = cur.left;//cur走到原节点的左孩子节点
            }
            //当左子树走完,cur.left肯定会走到空节点,这时候就要走右子树了
            TreeNode top = stack.pop();//弹出栈顶节点,注意是弹出,不然会影响后遍历上一个节点的右孩子节点
            cur = top.right;//cur走到上一个节点的右孩子节点
        }
        //栈空了,说明遍历完了所有节点
        System.out.println();
    }

⭐非递归中序遍历

// 非递归实现中序遍历
    public void FDG_inOrderTraversal(TreeNode root) {
       if (root == null) {//先判断根节点是否空
            return;//第一个根节点如果空的话,就直接返回了
        }
        TreeNode cur = root;//设置临时节点cur,通过这个节点来遍历整棵树
        Stack<TreeNode> stack = new Stack<TreeNode>();//创建一个栈
        while(cur != null || !stack.isEmpty()) {//外循环,先写内循环采写外循环,只要栈不为空,说明还没遍历完成
            while (cur != null) {//内循环
                stack.push(cur);//将当前cur节点入栈,但不打印,需要用它来找左右孩子节点
                cur = cur.left;//cur走到原节点的左孩子节点
            }
            //当左子树走完,cur.left肯定会走到空节点,这时候就要走右子树了
            TreeNode top = stack.pop();//弹出栈顶节点,注意是弹出,不然会影响后遍历上一个节点的右孩子节点
            System.out.print(top.value+" ");//打印cur节点,中序遍历是在节点出栈后打印
            cur = top.right;//cur走到上一个节点的右孩子节点
        }
        //栈空了,说明遍历完了所有节点
        System.out.println();
    }

⭐非递归后序遍历

//非递归后续遍历
   public void postOrderTraversalNor(TreeNode root) {
        if(root == null) return;//第一个根节点如果空的话,就直接返回了
        TreeNode cur = root;//设置临时节点cur,通过这个节点来遍历整棵树
        Stack<TreeNode> stack = new Stack<>();//创建一个栈
        TreeNode pre = null;//用来指定 上一个被打印的元素
        while (cur != null || !stack.empty()) {//外循环,只要栈不为空,说明还没遍历完成
            while (cur != null) {//内循环
                stack.push(cur);//将当前cur节点入栈,但不打印,需要用它来找左右孩子节点
                cur = cur.left;//cur走到原节点的左孩子节点
            }
            cur = stack.peek();//查看栈顶节点
            if (cur.right == null || cur.right == pre) {//如果栈顶节点的右节点为空,或者已经遍历过了
                TreeNode popNode = stack.pop();//弹出栈顶节点并打印
                System.out.print(popNode.value + " ");
                pre = cur;//用pre将遍历(打印)过的节点记录下来
                cur = null;//cur要置空,不然就又来一遍了,置空后可以继续查看下一个栈顶节点而不进入内循环
            } else {//若栈顶节点右节点不为空
                cur = cur.right;//则遍历这个右节点
            }
        }
        System.out.println();
    }


🗽大厂OJ面试题


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


题目:

40.png

思路:

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

41.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. 二叉树的分层遍历


题目:

42.png

思路:

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

43.png


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


44.png

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

46.gif



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

47.png


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

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

48.gif


实现代码:

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
     //建立一个二维数组来记录每一层的情况
     List<List<Integer>> list = new ArrayList();
     Queue<TreeNode> queue = new LinkedList<>();//用队列实现层序遍历
        if (root==null){
            return list;
        }
        queue.offer(root);//根节点先入队
        while(!queue.isEmpty()) {
            int n = queue.size();//记录每一层有多少个节点,循环n次
            List<Integer> level = new ArrayList();//每一层用一个数组记录
            for(int i = 0 ; i<n ; i++){//弹出当前层里的节点,
            // 变量 i 无实际意义,只是为了循环 n 次
                TreeNode top = queue.poll();//弹出队头节点
                level.add(top.val);//将弹出的节点加入它所在的那一层
                //弹出的时候不要忘了将弹出节点的孩子节点入队
                if (top.left != null) {
                    queue.offer(top.left);
                }
                if (top.right != null) {
                    queue.offer(top.right);
                }
            }
            list.add(level);//将每一层添加到二维数组中
        }
        return list;//最后返回二维数组即为所求
    }
}



相关文章
|
5月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
241 3
|
7月前
|
前端开发 Java
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
198 1
|
7月前
|
存储 Java 编译器
Java 中 .length 的使用方法:深入理解 Java 数据结构中的长度获取机制
本文深入解析了 Java 中 `.length` 的使用方法及其在不同数据结构中的应用。对于数组,通过 `.length` 属性获取元素数量;字符串则使用 `.length()` 方法计算字符数;集合类如 `ArrayList` 采用 `.size()` 方法统计元素个数。此外,基本数据类型和包装类不支持长度属性。掌握这些区别,有助于开发者避免常见错误,提升代码质量。
649 1
|
11月前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
165 5
|
12月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
196 6
|
Java
java实现简单的二叉树ADT
java实现简单的二叉树ADT
220 0
|
Java 程序员
java实现简单二叉树
java实现简单二叉树
433 0
java实现简单二叉树
用Java实现一个简单二叉树
前置知识: 什么是二叉树:一个递归的树形数据结构,每个节点最多有两个子节点;二叉树一般都是二分查找树,每个节点的值大于它左子节点的值,小于它右子节点的值
895 0
用Java实现一个简单二叉树
|
1月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
103 1
|
1月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
111 1

热门文章

最新文章