二叉树的递归层序遍历

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

二叉树的递归/层序遍历

1. 递归遍历(DFS)

递归遍历二叉树的代码如下:

class TreeNode {
    int val;
    TreeNode left, right;
}

public void traverse(TreeNode root) {
    if (root == null) {
        return;
    }
    // 进行遍历
    traverse(root.left);
    traverse(root.right);
}

traverse 函数的遍历顺序,就是一直往左节点走,左节点走不下去了,再往右节点走,然后又开始往左节点走,循环往复,直到左右节点都遍历完了,就返回父节点。看代码也能看出来,先调用 root.left,再调用 root.right,一定是先往左节点走,碰到 null 才开始往右节点走一次

只要遵循先左再右的规则,traverse 函数访问节点的顺序就是固定的,插入多少条数据都不会发生变化。那有人问了,为什么之前学的数据结构会分为,前序遍历、中序遍历、后序遍历等不同的方式,这是为什么?

所谓的前序遍历这些方式,指的是在不同的时机将对节点进行操作(例如打印节点)。

public void traverse(TreeNode root) {
    if (root == null) {
        return;
    }
    //前序遍历
    traverse(root.left);
    // 中序遍历
    traverse(root.right);
    // 后序遍历
}

前序位置的代码会在进入节点时立即执行;中序位置的代码会在左子树遍历完成后,遍历右子树之前执行;后序位置的代码会在左右子树遍历完成后执行

特别强调,三种位置的不同关键是操作的时机不同,而二叉树遍历的的轨迹不会发生变化(先左再右)。在实际的算法题中,不会要求你写前中后序遍历的,关键在于把正确的代码写到正确的位置。

2. 层序遍历(BFS)

层序遍历,顾名思义,一层一层的进行遍历,从上到下,从左到右。层序遍历需要依赖队列来实现,可以分为三种方式来实现。补个关于队列的 API 的小知识点:

  • add(E e):向队尾添加元素;队列满时抛异常
  • offer(E e):向队尾添加元素;队列满时返回 false(不抛异常)。
  • remove():移除并返回队头元素;队列空时抛异常
  • poll():移除并返回队头元素;队列空时返回 null(不抛异常)。
  • element():返回队头元素(不移除);队列空时抛异常
  • peek():返回队头元素(不移除);队列空时返回 null

写法一

public void levelOrderTraverse(TreeNode root) {
    if (root == null) {
        return;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    while (!queue.isEmpty()) {
        // 开始将头部的元素移除
        TreeNode cur = queue.poll();
        System.out.println(cur.val);
        // 随后将 cur 的左右节点放到队列中
        if (cur.left != null) {
            q.offer(cur.left);
        }
        if (cur.right != null) {
            q.offer(cur.right);
        }
    }
}

这种写法是最简单的,每次先将队头元素取出来,再将其左右节点放到队列尾部,就成了,但是缺点也明显,无法得知当前节点的在哪一层,这个需求挺常见的,比如:收集某一层的节点,或者找出二叉树的最小深度等等。

写法二

public void levelOrderTraverse(TreeNode root) {
    if (root == null) {
        return;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    // 记录当前遍历到的层数(根节点视为第 1 层)
    int depth = 1;
    while (!queue.isEmpty()) {
        // 可以使用一个 size() 方法,得知当前队列内有多少元素,这些元素都在一层的
        int sz = queue.size();
        for (int i = 0; i < sz; i++) {
            TreeNode cur = queue.poll();
            // 访问 cur 节点,同时打印 cur 所在的位置(哪一层depth)
            System.out.println("depth = " + depth + ", val = " + cur.val);
            // 将 cur 的左右节点放到队尾
            if (cur.left != null) {
                queue.offer(cur.left);
            }
            if (cur.right != null) {
                queue.offer(cur.right);
            }
        }
        depth++;
    }
}

这种写法就可以记录下来每个节点所在的层数,可以解决诸如二叉树最小深度这样的问题,是我们最常用的层序遍历写法。

写法三

回顾一下写法二,每往下走一层,depth 进行+1操作,是不是可以理解为每条树枝的权重是1,二叉树的每个节点是不是可以理解为:根节点到该节点的路径权重和,但是吧,同一层的节点,它们的路径权重和是不是一样的?

那么假设,每个节点的路径权重和是任意数,让你层序遍历每个节点,打印其的路径权重和,你会怎么办?那么,每一层的节点的路径权重和就和之前不一样了,写法二这种只使用一个 depth 变量就无法满足需求了。

写法三就是为了解决这个问题,在方法一的基础上写一个 State 类,让每个节点自己负责维护自身的路径权重。

class State {
    TreeNode node;
    int depth;
    
    State(TreeNode node, int depth) {
        this.node = node;
        this.depth = depth;
    }
}

public void levelOrderTarverse(TreeNode root) {
    if (root == null) {
        return;
    }
    Queue<State> queue = new LinkedList<>();
    // 根节点的路径权重和是 1
    queue.offer(new State(root, 1));
    while (!queue.isEmpty()) {
        State cur = queue.poll();
        // 再访问 cur 节点的同时,打印其权重路径和 
        System.out.println("depth:" + cur.depth + ",val = " + cur.node.val);
        // 再将 cur 左右节点放到队尾中
        if (cur.node.left != null) {
            queue.offer(new State(cur.node.left, cur.depth + 1));
        }
        if (cur.node.right != null) {
            queue.offer(new State(cur.node.right, cjur.depth + 1));
        }
    }
}

这样每个节点都有了自己的 depth 变量,是最灵活的,可以满足所有 BFS 算法的需求。但是由于要额外定义一个 State 类比较麻烦,所以非必要的话,用写法二就够了。

接下来,你就可以无痛完成下面这几道题了

力扣难度
102. 二叉树的层序遍历🟠
144. 二叉树的前序遍历🟢
145. 二叉树的后序遍历🟢
94. 二叉树的中序遍历🟢
二叉树层序遍历分层[递归迭代两种思想+三种解法] 层序遍历作为二叉树遍历的基本遍历,一般来说只能用迭代来解。但是分层输出则既可用迭代,又可配合level用前序遍历来解。 阅读详情

相关推荐

C++ | 二叉树前序、中序、后序遍历的递归和非递归实现 +层序遍历+深度优先遍历

二叉树的遍历是学习二叉树最基本却极为重要的一环。当你熟练掌握二叉树的遍历之后,你会发现很多题目都是建立在遍历的基础上来解决的,

湫一 6497

二叉树遍历-层序-递归

二叉树遍历、层序遍历:从上往下,从左到右。使用广度优先搜索算法

he_xin2009的专栏 2665

SAP CO-PA数据传送避坑指南:销售开票与FI/MM记账的日常配置实操(含KEKF/KE4I/KEI2)

本文深入解析SAP CO-PA数据传送中的常见配置问题,特别是销售开票与FI/MM记账环节的实操避坑指南。通过KEKF/KE4I/KEI2等关键配置点的详细说明,帮助用户避免数据失真和重复记录,提升获利能力分析的准确性。文章结合实战案例,揭示官方文档未提及的'数据黑洞'形成机制,为SAP顾问提供实用的排雷手册。

weixin_26905487的博客 373

二叉树递归遍历和层序遍历(c/c++)

递归遍历: 二叉树的三种递归遍历为先序遍历,中序遍历和后续遍历。它们相似之处在于都是对二叉树递归遍历且对任何一个结点都经过三次,区别在于哪一次对该结点进行访问,由此分为先,中,后序遍历。所以对于任一结点都有:三次经过,一次访问。 先序遍历: 仅以先序遍历为例,其思路是,当我们对二叉树进行遍历时,先对该结点内的数据进行访问,然后依次遍历它的左右孩子结点,递归进行直至结束。 例:对一个有三个结...

Little_ant_的博客 3527

二叉树层序遍历递归和迭代法)

二叉树层序遍历递归和迭代法)

weixin_44640001的博客 1218

【数据结构】-----二叉树递归、层次实现二叉树的遍历)

递归实现二叉树前序遍历 递归实现二叉树中序遍历 递归实现二叉树后序遍历 二叉树的销毁 二叉树层序遍历(用队列实现二叉树节点个数 二叉树叶子节点个数 二叉树第k层节点个数 二叉树查找值为x的节点 二叉树深度/高度

m0_55752775的博客 2765

二叉树层序遍历(两种方法:迭代+递归

借助一个队列,层层遍历,将每一层的节点入队,出队时由于队列先进先出的特点,也会按顺序出队。在出队前,我们先计算队列的长度len,这个长度len就相当于当前层一共有len个节点,所以我们只需要将len个节点出队即可,其他的节点都是下一层的,我们先不去管,所以在循环出队时,结束条件就是len=0。递归也就是我们常说的深度优先遍历,需要设置一个index,用来记录遍历到哪一层了,将节点放入到自己的层中。输入:root = [3,9,20,null,null,15,7]输出:[[3],[9,20],[15,7]]

m0_58681055的博客 934

二叉树层序遍历递归与非递归

递归实现: 计算二叉树的高度 逐层打印: 例如打印二叉树的第k层,可以看作以root-&gt;_left为根节点,打印它的k-1层,然后以root-&gt;_right为根节点,打印它的k-1层,直到k==1。 void _BTreeLevelOrder(BTNode* root, size_t i) { if (root == NULL || i == 0)...

苍老的小孩的博客 2万+

二叉树的前中后和层序遍历详细图解(递归和非递归写法)

我家门前有两棵树,一棵是二叉树,另一棵也是二叉树。 遍历一棵二叉树常用的有四种方法,前序(PreOrder)、中序(InOrder)、后序(PastOrder)还有层序(LevelOrder)。 前中后序三种遍历方式都是以根节点相对于它的左右孩子的访问顺序定义的。例如根-&gt;左-&gt;右便是前序遍历,左-&gt;根-&gt;右便是中序遍历,左-&gt;右-&gt;根...

Monster_ii的博客 8万+

二叉树层序遍历(迭代法和递归法)

二叉树的相关操作中,层序遍历是一种重要的遍历方式,它按照二叉树的层次结构,从根节点开始,逐层地遍历节点,使得同一层的节点按照从左到右的顺序被访问。

Hhjhj255的博客 1921

树、二叉树的前中后层序遍历递归、非递归Java实现

文章目录1. 二叉树的前中后序遍历(递归,非递归)以及层序遍历1.1 二叉树前中后遍历的递归解法1.2 二叉树前中后遍历的非递归解法1.2.1 非递归的前序遍历:(LeetCode 144)1.2.2 非递归的中序遍历:(LeetCode 94)1.2.3 非递归的后序遍历:(LeetCode 145)1.3 层序遍历:(LeetCode 102、103、107)2 树的前中后层序遍历2.1 前序...

卤小蛋学编程 5071

LeetCode——二叉树层序遍历递归与非递归

题目描述 递归实现 递归实现主要是在函数内部定义一个新的函数,这个函数接收两个参数,一个是当前节点,一个是层次,如果当前节点为空的话,则返回空,如果当前节点不为空,判断二维数组的指定位置是否为空,如果存在则push进当前节点的val值,如果不存在则设置为空数组,然后递归遍历左子树,层次+1,递归遍历右子树的时候层次还是+1。 var levelOrder = function(root) { // 定义最终的返回结果 const res = []; function levelOrder(

Always-Learning 3220

三行代码递归实现二叉树层序遍历

简述 二叉树层序遍历网上大部分都是使用队列的出队和入队来实现的,这次我用三行代码递归实现二叉树层序遍历. 层序 下图是一个简单的二叉树,层序就是一行一行的往下读取,这个二叉树的层序结果便是: 1234567 (图画的比较丑,强迫症看着难受,看官忍一下) 递归分析 要想使用递归,必须有两个条件: 函数参数类型相同 递归必须有出口 在二叉树中找到上面的两个条件,与

郝凡的博客 7611

二叉树遍历全解析:递归、非递归层序遍历

二叉树是计算机科学中最重要的数据结构之一,广泛应用于算法设计、数据库索引、文件系统等领域。是操作树结构的基础,本文将全面讲解前序、中序、后序遍历的递归与非递归实现,以及层序遍历实现,并深入探讨它们的应用场景和底层原理。

lzy040215的博客 879

二叉树层序遍历递归和非递归算法

二叉树层序遍历递归和非递归算法

xmg26的博客 4550

二叉树递归/层序遍历

回顾写法二,我们每向下遍历一层,就给 depth 加 1,可以理解为每条树枝的权重是 1,二叉树中每个节点的深度,其实就是从根节点到这个节点的路径权重和,且同一层的所有节点,路径权重和都是相同的。知道节点的层数是个常见的需求,比方说让你收集每一层的节点,或者计算二叉树的最小深度等等。这种写法就可以记录下来每个节点所在的层数,可以解决诸如二叉树最小深度这样的问题,是我们最常用的层序遍历写法。那么假设,如果每条树枝的权重和可以是任意值,现在让你层序遍历整棵树,打印每个节点的路径权重和,你会怎么做?

xiangfengweixiaojie的博客 559

二叉树的前序、中序、后序、层序遍历,Java实现(递归、非递归)

关于二叉树的内容,我觉得二叉树最核心的地方就是它的几种遍历方式,基本上所有的问题都是围绕着几种遍历方式来的。因此就在这总结一下这几种遍历方式。 前序遍历 一、简介 前序遍历(DLR),是二叉树遍历的一种,也叫做先根遍历、先序遍历,可记做根左右。 前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树。 若二叉树为空则结束返回,否则...

丸啊~ 6907

二叉树递归和非递归层序遍历

递归层序遍历二叉树 //非递归层序遍历 public void sequenceTraversal(){ //每一层加入队列的节点个数 int num=0; //当前层下一层的入队节点个数 int nextNum=0; //每一层已经遍历的节点个数 int alreadyNum=0; //存放节点的队列 Queue queue=new Queue(); /

weixin_44911106的博客 274

层序遍历递归删除二叉树

从叶节点开始向根节点的方向逐层删除。直观的讲,对于以下二叉树递归删除的次序为:f -> g -> h -> i -> d -> e -> b -> c -> a。

AncilunKiang的博客 223

二叉树递归遍历 迭代法遍历二叉树 层序遍历

首先,二叉树的结构体,有值域,有左右指针,其实对于这三种方式,只是顺序略有不同,其他的都一样,以前序遍历为例,在这里我们用cur指针做遍历操作,如果cur指向空,就回退,先取中节点的值,然后递归左子树,之后再递归右子树,前提是要有左右子树,顺序就是先中节点,后左子树,最后右子树。当cur不为空或栈不为空时,将cur放入栈中,之后cur=cur->left,直到左子树为空,这时将栈顶元素pop出,放置于数组中,然后cur=cur->right,如果存在右子树就将其放入栈中,就这样,循环下去,最终遍历结束。

2301_82195117的博客 894
上一篇: AI应用生成平台:模型调用与工具集成
下一篇: 多叉树的递归层序遍历
Join2049
博客等级 码龄3年 707粉丝 76原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值