树结构--介绍--二叉树遍历的递归实现

简介: 树结构--介绍--二叉树遍历的递归实现

是一种非线性的数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

  • 每个节点有零个或多个子节点;
  • 没有父节点的节点称为根节点;
  • 每一个非根节点有且只有一个父节点;
  • 除了根节点外,每个子节点可以分为多个不相交的子树

树的学术名词

  • 根节点(root): 树的最上层的节点,任何非空的树都有一个节点
  • 路径(path): 从起始节点到终止节点经历过的边
  • 父亲(parent):除了根节点,每个节点的上一层边连接的节点就是它的父亲(节点)
  • 孩子(children): 每个节点由边指向的下一层节点
  • 兄弟(siblings): 同一个父亲并且处在同一层的节点
  • 子树(subtree): 每个节点包含它所有的后代组成的子树
  • 叶子节点(leaf node): 没有孩子的节点成为叶子节点

树的种类

无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树;


有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;


二叉树:每个节点最多含有两个子树的树称为二叉树;


满二叉树:所有节点均含有两个子树的树被称为满二叉树;


完全二叉树:除最后一层外,所有层都是满节点,且最后一层缺右边连续节点的二叉树称为完全二叉树;


哈夫曼树(最优二叉树):带权路径最短的二叉树称为哈夫曼树或最优二叉树。

二叉树的遍历

所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问


访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础


算法实现

从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:

  • 访问节点的本身(Node)
  • 遍历该节点的左子树(L)
  • 遍历该节点的右子树 (R)

以上三种操作拥有六种执行顺序:

NLR,LNR,LRN,NRL,RNL,RLN。

但是注意前三种次序和后三种次序对称,所以我们只学习前三种次序

遍历命名

根据访问结点操作发生位置命名:

  • NLR:二叉树的前序遍历(Prreorder Traversal 亦称(先序遍历))
    访问根结点的操作发生在遍历其左右子树之前
  • LNR:二叉树的中序遍历(Inorder Traversal)
    访问根结点的操作发生在遍历其左右子树之中(间)
  • LRN:二叉树的后序遍历(Postorder Traversal)
    访问根结点的操作发生在遍历其左右子树之后

二叉树的中序遍历

若二叉树非空,则依次执行如下操作:

  1. 遍历左子树
  2. 访问根节点
  3. 遍历右子树

# 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 inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
    # 左 根 右
    def inorder(root : TreeNode):
      if not root:
        return
      inorder(root.left)
      res.append(root.val)
      inorder(root.right)
    res = list()
    inorder(root)
    return res

二叉树的后序遍历

若二叉树非空,则依次执行如下操作:

  1. 遍历左子树
  2. 遍历右子树
  1. 访问根节点

# 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 postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
    # 后序遍历的顺序:左 右 根
    def postorder(root : TreeNode):
      if not root:
        return
      postorder(root.left)
      postorder(root.right)
      res.append(root.val)
    res = list()
    postorder(root)
    return res

二叉树的后序遍历迭代算法

  1. 建立一个栈,用来存储节点。
  2. 根据根右左的顺序将节点依次压入栈中,在压入栈中的同时,按照顺序把节点里的元素依次压入栈中。输出完毕之后按照顺序弹栈。
  3. 将答案数组进行反转,得到左右根顺序的数组
  1. 输出答案

期望结果:[9,5,7,4,3]

# 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 postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
    res = []
    stack = []
    while root or stack:
      while root:
        res.append(root.val)
        stack.append(root)
        root = root.right
      root = stack.pop().left #根 右 左的顺序
    res.reverse() 
    return res

二叉树的前序遍历

若二叉树非空,则依次执行如下操作:

  1. 访问根节点
  2. 遍历左子树
  3. 遍历右子树

class Solution:
  def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
    # 创建一个集合存储数据
    res = []
    def preorder(root:TreeNode):
      # 判断root是否有值
      if not root:
        return
      else:
        # 获取根节点
        res.append(root.val)
        # 获取左节点
        preorder(root.left)
        # 获取右节点
        preorder(root.right)
    preorder(root)
    return res

二叉树的前序遍历迭代算法

  1. 建立一个栈,用来存储节点。
  2. 根据左右根的顺序将节点依次压入栈中,在压入栈中的同时,按照顺序把节点里的元素依次压入栈中。输出完毕之后按照顺序弹栈。
  1. 输出答案。
class Solution:
  def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
    # 创建res存储结果
    res = []
    stack = [] # 存储分支节点
    # 只要root有数据 或者stack的数据
    while root or stack:
      # 只要root有数据,第一轮循环把左节点搞定
      while root:
        res.append(root.val)
        stack.append(root)
        # 获取左节点
        root = root.left
      # 取出右节点,遍历
      root = stack.pop().right
    return res
相关文章
|
存储 人工智能 Apache
Apache Paimon多模态数据湖实践:从结构化到非结构化的技术演进
在Streaming Lakehouse Meetup中,Apache Paimon PMC叶俊豪分享了Paimon多模态数据湖创新:首创列分离架构(基于全局Row ID),解决AI场景下结构化特征动态变更难题;引入Blob类型,实现非结构化数据物理分离、跨引擎统一抽象与blob-as-descriptor流式加载;已支撑淘宝日均10PB多模态数据,并规划Deletion Vector、Blob Compaction及全局索引等演进。
714 0
Apache Paimon多模态数据湖实践:从结构化到非结构化的技术演进
|
5月前
|
存储 数据安全/隐私保护 iOS开发
《锚定App Store生态:编程工具上架零踩坑的核心操作指南》
本文聚焦iOS App Store编程工具上架的核心痛点,深度拆解隐私合规、功能一致性、性能兼容性、版权边界四大高频驳回场景,结合真实案例给出可落地的整改方案。从隐私政策精细化撰写、IDFA授权规范,到功能描述与实际落地的匹配、启动速度与内存优化,再到开源组件授权核查与功能边界把控,全面覆盖上架关键环节。同时分享科学应对驳回的沟通策略与预审机制,帮助开发者从开发初期锚定平台规则,规避常见坑点。文章旨在破解App Store审核逻辑,为编程工具开发者提供“零驳回”上架的实战指南,助力工具高效通过审核,快速触达核心用户。
198 2
|
7月前
|
机器学习/深度学习 算法 数据可视化
PINN物理信息神经网络用于求解二阶常微分方程(ODE)的边值问题研究(Matlab代码实现)
PINN物理信息神经网络用于求解二阶常微分方程(ODE)的边值问题研究(Matlab代码实现)
424 6
|
10月前
|
机器学习/深度学习 人工智能 算法
如何像 Manus 交付业务需求-- OneAgent + MCPs 范式
本文探讨了从单一LLM调用到复杂Agent系统的发展历程,重点介绍了OneAgent + MCPs范式。该范式通过结合强大的基础Agent和领域特定的MCP(Microservice Capability Provider)来解决复杂业务需求。文章分析了其在保险科技领域的实践,展示了如何通过Loop框架执行任务,并讨论了当前面临的挑战如to-do质量依赖、状态管理和知识整合深度等问题。同时,提出了包括标准化交互生态、提升系统鲁棒性、优化MCP调用管理及应用强化学习等发展方向。最终展望了这一范式在更多行业落地的潜力,强调了快速搭建领域Agent的重要性,而非追求全知全能的GodAgent模式。
如何像 Manus 交付业务需求-- OneAgent + MCPs 范式
|
8月前
|
人工智能 Ubuntu Unix
第 1 章 Linux 快速入门
Mainline 表示主线开发版本,Stable 表示稳定版本,稳定版本主要由 mainline 测试通过而发布。Longterm 表示长期支持版,会持续更新及 Bug 修复,如果长期版本被标记为 EOL(End of Life),则表示不再提供更新。
295 0
|
人工智能
新手必看,写歌词的技巧和方法新分享,妙笔生词AI智能写歌词软件
对于新手,写歌词不再难。本文分享了写歌词的实用技巧,如积累生活素材、明确主题、合理安排主副歌、简洁有力的语言表达等。推荐使用“妙笔生词智能写歌词软件”,其AI功能可助你灵感不断,轻松创作。
|
9月前
|
数据采集 监控 安全
拼多多API价格战预警:竞品监控不落人后!
在电商竞争激烈的当下,拼多多凭借低价策略迅速崛起,但也给商家带来定价挑战。本文解析如何利用API技术,构建实时价格预警与竞品监控系统,助力商家在价格战中抢占先机,实现智能调价与策略应对。
726 0
|
网络协议 网络虚拟化 数据中心
|
编译器 C++ 容器
C++零基础教程(拷贝构造函数)
C++零基础教程(拷贝构造函数)
338 1
|
人工智能 算法 安全
强 AI 和弱 AI 之间的区别
强 AI 和弱 AI 之间的区别