【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;//最后返回二维数组即为所求
    }
}



相关文章
|
4天前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
32 8
|
27天前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
16 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
27天前
|
存储 算法 搜索推荐
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
这篇文章主要介绍了顺序存储二叉树和线索化二叉树的概念、特点、实现方式以及应用场景。
17 0
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
|
27天前
|
存储 算法
探索数据结构:分支的世界之二叉树与堆
探索数据结构:分支的世界之二叉树与堆
|
27天前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
22 0
|
5天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
64 9
|
2天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
4天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
26 4
|
28天前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
26 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
8天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!