• 二叉树之前序遍历、中序遍历和后序遍历


    0 引言

    本文主要学习数据结构中的二叉树,包括常用的三种遍历方法:前序遍历、中序遍历和后序遍历。

    1 二叉树

    1.1 定义

    二叉树是一种常见的树状数据结构,它由节点组成,每个节点最多有两个子节点,分别称为左子节点和右子节点。每个节点可以存储一个值或者其他相关信息。

    1.2 特点

    1. 每个节点最多有两个子节点,且左子节点和右子节点的顺序是固定的。左子节点位于父节点的左侧右子节点位于父节点的右侧。这种结构可以直观地表示许多问题,例如树形结构、有序列表等。
    2. 二叉树可以为空,即没有节点。如果一个节点没有子节点,则称为叶子节点或终端节点。除了叶子节点外,每个节点都有一个父节点,除了根节点外,每个节点都有一个唯一的父节点。
    3. 二叉树可以具有不同的特殊形式,例如二叉搜索树Binary Search Tree),其中左子节点的值小于等于父节点的值,右子节点的值大于等于父节点的值。还有平衡二叉树Balanced Binary Tree),其中左子树和右子树的高度差不超过一。
    4. 二叉树的遍历是指按照一定的顺序访问树中的节点。常见的遍历方式包括前序遍历Pre-order),中序遍历In-order),后序遍历Post-order)。这些遍历方式可以帮助我们有效地处理二叉树中的节点。

    2 前序遍历

    前序遍历(Pre-order traversal)是一种二叉树遍历的方式,它按照根节点、左子树、右子树的顺序访问二叉树中的节点。

    具体来说,前序遍历的步骤如下:

    1. 访问当前节点(根节点)。
    2. 递归地前序遍历左子树。
    3. 递归地前序遍历右子树。

    可以使用递归或迭代的方式实现前序遍历。

    递归实现前序遍历的伪代码如下

    preorderTraversal(node):
        if node is null:
            return
        访问当前节点(输出节点的值或进行其他操作)
        preorderTraversal(node.left)  # 递归前序遍历左子树
        preorderTraversal(node.right)  # 递归前序遍历右子树
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    迭代实现前序遍历通常使用栈(Stack)数据结构辅助完成。算法步骤如下:

    1. 创建一个空栈,并将根节点入栈。
    2. 当栈不为空时,执行以下操作:
      • 弹出栈顶节点,并访问该节点(输出节点的值或进行其他操作)。
      • 将右子节点(如果存在)入栈。
      • 将左子节点(如果存在)入栈。
      • 注意:由于栈是后进先出(LIFO)的数据结构,所以先入栈右子节点,再入栈左子节点,以确保左子节点在右子节点之前被访问。

    迭代实现前序遍历的伪代码如下

    preorderTraversal(node):
        if node is null:
            return
        创建一个空栈
        将根节点入栈
        while 栈不为空:
            弹出栈顶节点并访问该节点
            如果节点的右子节点不为空,将右子节点入栈
            如果节点的左子节点不为空,将左子节点入栈
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    无论是递归实现还是迭代实现,前序遍历会按照根节点、左子树、右子树的顺序遍历二叉树中的节点。这种遍历方式在某些问题的解决中非常有用,例如复制一棵二叉树、表达式求值等。

    3 中序遍历

    中序遍历In-order traversal)是一种二叉树遍历的方式,它按照左子树、根节点、右子树的顺序访问二叉树中的节点。

    具体来说,中序遍历的步骤如下:

    1. 递归地中序遍历左子树。
    2. 访问当前节点(根节点)。
    3. 递归地中序遍历右子树。

    可以使用递归或迭代的方式实现中序遍历。

    递归实现中序遍历的伪代码如下

    inorderTraversal(node):
        if node is null:
            return
        inorderTraversal(node.left)  # 递归中序遍历左子树
        访问当前节点(输出节点的值或进行其他操作)
        inorderTraversal(node.right)  # 递归中序遍历右子树
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    迭代实现中序遍历通常使用栈(Stack)数据结构辅助完成。算法步骤如下:

    1. 创建一个空栈。
    2. 初始化当前节点为根节点。
    3. 当栈不为空或当前节点不为空时,执行以下操作:
      • 将当前节点以及其所有左子节点依次入栈,直到当前节点为空。
      • 弹出栈顶节点,访问该节点(输出节点的值或进行其他操作)。
      • 将当前节点指向弹出节点的右子节点。

    迭代实现中序遍历的伪代码如下

    inorderTraversal(node):
        创建一个空栈
        初始化当前节点为根节点
        while 栈不为空 或者 当前节点不为空:
            将当前节点以及其所有左子节点依次入栈,直到当前节点为空
            弹出栈顶节点并访问该节点
            将当前节点指向弹出节点的右子节点
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    无论是递归实现还是迭代实现,中序遍历会按照左子树、根节点、右子树的顺序遍历二叉树中的节点。中序遍历常用于对二叉搜索树进行排序,也可以用于在二叉树中查找节点或执行其他与节点顺序相关的操作。

    4 后序遍历

    后序遍历Post-order traversal)是一种二叉树遍历的方式,它按照左子树、右子树、根节点的顺序访问二叉树中的节点。

    具体来说,后序遍历的步骤如下:

    1. 递归地后序遍历左子树。
    2. 递归地后序遍历右子树。
    3. 访问当前节点(根节点)。

    可以使用递归或迭代的方式实现后序遍历。

    递归实现后序遍历的伪代码如下

    postorderTraversal(node):
        if node is null:
            return
        postorderTraversal(node.left)  # 递归后序遍历左子树
        postorderTraversal(node.right)  # 递归后序遍历右子树
        访问当前节点(输出节点的值或进行其他操作)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    迭代实现后序遍历通常使用栈(Stack)数据结构辅助完成。算法步骤如下:

    1. 创建两个栈,一个用于存储节点,另一个用于存储后序遍历的结果。
    2. 初始化当前节点为根节点,并将其入栈。
    3. 当节点栈不为空时,执行以下操作:
      • 弹出栈顶节点,将其压入结果栈。
      • 如果弹出节点的左子节点不为空,将左子节点入节点栈。
      • 如果弹出节点的右子节点不为空,将右子节点入节点栈。
    4. 当节点栈为空时,所有节点已遍历完毕。将结果栈中的节点依次弹出,即为后序遍历的结果。

    迭代实现后序遍历的伪代码如下

    postorderTraversal(node):
        创建一个节点栈
        创建一个结果栈
        将根节点入节点栈
        while 节点栈不为空:
            弹出栈顶节点并将其压入结果栈
            如果弹出节点的左子节点不为空,将左子节点入节点栈
            如果弹出节点的右子节点不为空,将右子节点入节点栈
        while 结果栈不为空:
            弹出结果栈顶节点并访问该节点(输出节点的值或进行其他操作)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    无论是递归实现还是迭代实现,后序遍历会按照左子树、右子树、根节点的顺序遍历二叉树中的节点。后序遍历常用于释放二叉树的内存资源、计算表达式的值等场景,也可以用于执行其他与节点顺序相关的操作。

    5 总结

    前序遍历:根节点->左子树->右子树

    中序遍历:左子树->根节点->右子树

    后序遍历:左子树->右子树->根节点

    如下图二叉树为例,前序遍历的详细步骤

    1. 前两层,只有一个根节点0,遍历结果:0->1->2
    2. 加上第三层,有两个根节点1,2,遍历结果:1->3->42->5->6,与上一步合在一起,3,4加在1的后边,5,6加在2的后边,遍历结果:0->1->3->4->2->5->6
    3. 加上第四层,又有两个根节点3,4,遍历结果:3->7->84->9,与上一步合在一起,7,8加在3的后边,9加在4的后边,遍历结果:0->1->3->7->8->4->9->2->5->6

    中序遍历的详细步骤

    1. 前两层,只有一个根节点0,遍历结果:1->0->2
    2. 加上第三层,有两个根节点1,2,遍历结果:3->1->45->2->6,与上一步合在一起,3,4分别加在1的前边和后边,5,6也分别加在2的前边和后边,遍历结果:3->1->4->0->5->2->6
    3. 加上第四层,又有两个根节点3,4,遍历结果:7->3->89->4,与上一步合在一起,7,8分别加在3的前边和后边,9加在4的前边,遍历结果:7->3->8->1->9->4->0->5->2->6

    后序遍历的详细步骤

    1. 前两层,只有一个根节点0,遍历结果:1->2->0
    2. 加上第三层,有两个根节点1,2,遍历结果:3->4->15->6->2,与上一步合在一起,3,4加在1的前边,5,6加在2的前边,遍历结果:3->4->1->5->6->2->0
    3. 加上第四层,又有两个根节点3,4,遍历结果:7->8->39->4,与上一步合在一起,7,8加在3的前边,9加在4的前边,遍历结果:7->8->3->9->4->1->5->6->2->0
      请添加图片描述



    须知少时凌云志,曾许人间第一流。



    ⭐️👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍🌔

  • 相关阅读:
    Vue.js核心技术解析与uni-app跨平台实战开发学习笔记 第2章 Vue.js绑定样式及案例 2.5 简单版购物车案例
    C#通过C++操作共享内存和Python通讯[C#调用exe不显示窗口]
    基于安卓android微信小程序音乐播放器
    【3. 操作系统—物理内存管理】
    【Redis】3.详解分布式锁
    并发原理 — CPU原子性指令(一)
    基于jsp+mysql+ssm的校园OTO超市系统-计算机毕业设计
    序列和【牛客网】
    手把手教你如何Vue项目打包dist文件并Tomcat发布【超级详细】
    Linux多线程
  • 原文地址:https://blog.csdn.net/MRZHUGH/article/details/133302016