ACM 选手带你玩转二叉树前中后序遍历(递归版)

简介: ACM 选手带你玩转二叉树前中后序遍历(递归版)

大家好呀,我是在爬二叉树的帅蛋。


二叉树遍历的实现历来是面试的高频问题,关于二叉树的前中后序遍历有两种实现方式:递归和非递归


递归实现起来简单一些,而非递归的实现需要借助之前讲过的【】这个数据结构


这两种实现方式都需要蛋粉们牢牢掌握,我们先从简单的开始,先讲递归版的二叉树前中后序遍历。

640.jpg

关于递归,我之前写过一篇很详细的文章:


ACM 选手带你玩转递归算法!


没看过的蛋粉可以看一下。


说白了递归就是一种循环,一种自己调用自己的循环


一道题你看能不能用递归实现,需要具备两个条件


  • 问题可以分为多个重复的子问题,子问题仅存在数据规模的差距。
  • 存在终止条件。


所以根据条件,对于实现递归,只需要两步


  • 找出重复的子问题(递推公式)。
  • 终止条件。


话不多说,赶紧开整。

640.png


下面我用三道 LeetCode 题来给大家具体讲解二叉树前中后序遍历的递归版。

640.jpg

   二叉树前序遍历(递归版)



LeetCode 144:二叉树的前序遍历


给你二叉树根节点 root,返回它节点值的前序遍历


示例

640.png


输入:root = [1,null,2,3]
输出:[1,2,3]


解析


根据上面讲的实现递归的两步来找:


(1) 找出重复的子问题。


这个很好找,前序遍历的顺序是:根、左子树、右子树。


对于左子树或者右子树来说,也是同样的遍历顺序。


所以这个重复的子问题就出来了,先取根节点,再遍历左子树,最后遍历右子树

print(root.val)
preOrder(root.left)
preOrder(root.right)

(2) 确定终止条件。


对于二叉树的遍历来说,想终止,即没东西遍历了,没东西遍历自然就停下来了。


那就是当前的节点是空的,既然是空的那就没啥好遍历。

if root == None:
    return


最重要的两点确定完了,那总的代码也就出来了:


Python 代码实现


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    # 前序遍历函数
    def preOrder(self, root: TreeNode, res):
        if root == None:
            return
        res.append(root.val)
        self.preOrder(root.left, res)
        self.preOrder(root.right, res)
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
        self.preOrder(root, res)
        return res


Java 代码实现



class Solution {
    public void preOrder(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        res.add(root.val);
        preOrder(root.left, res);
        preOrder(root.right, res);
    }
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        preOrder(root, res);
        return res;
    }
}


此解法,由于每个节点被遍历一次,所以时间复杂度为 O(n)


额外维护了一个 res 列表,空间复杂度为 O(n)


   二叉树中序遍历(递归版)



LeetCode 94:二叉树的中序遍历


给你二叉树根节点 root,返回它的中序遍历。


示例

640.png


输入:root = [1,null,2,3]
输出:[1,3,2]


解析


同样根据上面讲的实现递归的两步来找:


(1) 找出重复的子问题。


中序遍历的顺序是:左子树、根、右子树。


对于左子树、右子树来说,也是同样的遍历顺序。


所以这个重复的子问题就是:先遍历左子树、再取根节点,最后遍历右子树

inOrder(root.left)
print(root.val)
inOrder(root.right)


(2) 确定终止条件。

和前序遍历相同,就是当前的节点为空,空的没啥好遍历的。

if root == None:
    return 


最重要的两点确定完了,那总的代码也就出来了:


Python 代码实现

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inOrder(self, root:TreeNode, res):
        if root == None:
            return
        self.inOrder(root.left, res)
        res.append(root.val)
        self.inOrder(root.right, res)
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
        self.inOrder(root, res)
        return res


Java 代码实现




class Solution {
    public void inOrder(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        inOrder(root.left, res);
        res.add(root.val);
        inOrder(root.right, res);
    }
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        inOrder(root, res);
        return res;
    }
}


和前序遍历相同,中序遍历时间复杂度为 O(n)空间复杂度为 O(n)


   二叉树后序遍历(递归版)



LeetCode 145:二叉树的后序遍历


给定一个二叉树,返回它的后序遍历。



示例

640.png

输入:root = [1,null,2,3]
输出:[3,2,1]


解析


还是根据上面讲的实现递归的两步来找:


(1) 找出重复的子问题。


后序遍历的顺序是:左子树、右子树、根,对于左子树、右子树来说,也是同样的遍历顺序。


所以这个重复的子问题就是:先遍历左子树、再遍历右子树、再取根节点。

postOrder(root.left)
postOrder(root.right)
print(root.val)


(2) 确定终止条件。

和前序遍历、中序遍历相同,就是当前的节点为空,空的没啥好遍历的。

if root == None:
    return 

最重要的两点确定完了,那总的代码也就出来了:


Python 代码实现


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def postOrder(self, root: TreeNode, res):
        if root == None:
            return
        self.postOrder(root.left, res)
        self.postOrder(root.right, res)
        res.append(root.val)
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
        self.postOrder(root, res)
        return res


Java 代码实现


class Solution {
    public void postorder(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        postorder(root.left, res);
        postorder(root.right, res);
        res.add(root.val);
    }
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        postorder(root, res);
        return res;
    }
}

和前序遍历、中序遍历相同,后序遍历时间复杂度为 O(n)空间复杂度为 O(n)



好啦,到这递归版的二叉树的前中后序遍历就讲完啦。


是不是蛋粉们觉得很简单?


如果因此你就小看了二叉树遍历,那你就图样图森破,非递归的二叉树遍历还是不那么简单的。


当然啦,我肯定不会说,不那么简单还是简单。


640.jpg





相关文章
|
数据库 数据安全/隐私保护 OceanBase
OceanBase数据库中,权限管理
OceanBase数据库中,权限管理
878 2
|
机器学习/深度学习 数据可视化 算法
ECA-Net:深度卷积神经网络的高效通道注意力
最近,**通道注意力机制**已被证明在提高深度卷积神经网络 (CNN) 的性能方面具有巨大潜力。然而,大多数现有方法致力于开发更复杂的注意力模块以获得更好的性能,这不可避免地增加了模型的复杂性。为了克服性能和复杂性权衡的悖论,**本文提出了一种高效通道注意 (ECA) 模块,该模块仅涉及少量参数,同时带来明显的性能增益**。通过剖析 SENet 中的通道注意模块,我们凭经验表明**避免降维对于学习通道注意很重要**,**适当的跨通道交互可以在显着降低模型复杂度的同时保持性能**。因此,**我们提出了一种无需降维的局部跨通道交互策略,可以通过一维卷积有效实现**。此外,**我们开发了一种自适应选
3536 0
ECA-Net:深度卷积神经网络的高效通道注意力
|
人工智能 Cloud Native 前端开发
Bolt.diy 测评:从零部署到创意实践的全流程体验
本文详细介绍了阿里云解决方案中的Bolt.diy工具,一款基于AI的开源全栈开发平台。通过自动部署方式,用户可快速体验其多模型适配、全栈开发等功能。文章涵盖从开通服务到部署应用的具体步骤,并结合实际案例展示了生成网页的效果与局限性。尽管Bolt.diy能显著提升建站效率,但在复杂需求处理和稳定性上仍有改进空间。建议优化代码生成实时查看、预览异常处理等问题,并增加更多学习资源以帮助用户更好地设计Prompt。
979 43
|
机器学习/深度学习 自然语言处理 算法
RAPTOR:多模型融合+层次结构 = 检索性能提升20%,结果还更稳健
本文探讨了通过多模型集成技术提升信息检索系统性能的方法,重点介绍了RAPTOR框架。RAPTOR通过构建层次化的信息组织结构和递归摘要技术,显著提高了检索系统的性能和适应性。研究建立在RAG Fusion技术基础上,旨在提供更全面的信息检索解决方案。
1248 2
RAPTOR:多模型融合+层次结构 = 检索性能提升20%,结果还更稳健
|
10月前
|
存储 SQL 分布式计算
MaxCompute x 聚水潭:基于近实时数仓解决方案构建统一增全量一体化数据链路
聚水潭作为中国领先的电商SaaS ERP服务商,致力于为88,400+客户提供全链路数字化解决方案。其核心ERP产品助力企业实现数据驱动的智能决策。为应对业务扩展带来的数据处理挑战,聚水潭采用MaxCompute近实时数仓Delta Table方案,有效提升数据新鲜度和计算效率,提效比例超200%,资源消耗显著降低。未来,聚水潭将进一步优化数据链路,结合MaxQA实现实时分析,赋能商家快速响应市场变化。
433 0
|
存储 人工智能
|
SQL 关系型数据库 MySQL
Vanna使用ollama分析本地数据库
这篇文章详细介绍了如何使用Vanna和Ollama框架来分析本地数据库,实现自然语言查询转换为SQL语句并与数据库交互的过程。
2912 7
Vanna使用ollama分析本地数据库
|
关系型数据库 MySQL 数据库
一个 MySQL 数据库死锁的案例和解决方案
本文介绍了一个 MySQL 数据库死锁的案例和解决方案。
964 3
|
运维 安全 Linux
在Linux中,如何排查系统启动问题?
在Linux中,如何排查系统启动问题?