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

二叉树,顾名思义,就是一个节点最多有两个子节点的树,要访问二叉树内的所有节点,我们一般有三种方法:前序遍历,中序遍历和后续遍历。

  • 前序遍历:访问顺序为“根-左-右
  • 中序遍历:访问顺序为“左-根-右
  • 后序遍历:访问顺序为“左-右-根

例如下面这颗二叉树:

前序遍历序列为:ABDGCEHIFJ

中序遍历序列为:DGBAHIECFJ

后序遍历序列为:GDBHIEJFCA

1、前序遍历代码

前序遍历的非递归需要用栈实现,实现过程如下:

  • 根节点入栈
  • 栈非空的时候,栈顶元素直接出栈,并将值放入结果中
  • 然后先后访问栈顶元素的右节点和左节点,并入栈(先右后左保证左节点先出)
  • 重复第二步,直到访问完所有元素

 代码实现:

def preorder_traversal_iterative(root):
    if root is None:
        return []
    stack = [root]
    res = []
    while stack:
        node = stack.pop()
        res.append(node.value)
        if node.right:
            stack.append(node.right)
        if node.left:
            stack.append(node.left)
    return res

2、中序遍历代码

中序遍历不仅要用到栈,还需要用到一个指针,来记录当前访问的元素,实现过程如下:

  • 将指针初始指向根节点,将所有左节点入栈
  • 弹出栈顶节点,并将节点的值存入结果
  • 访问栈顶元素的右节点

 这里要注意循环结束的条件是栈为空且当前指针也指向空。如果指针指向了空,但栈内还有元素,要继续弹出,若栈内没有元素,但当前指针还指向了非空节点,也需要继续入栈。

def inorder_traversal_iterative(root):
    if not root:
        return []
    stack = []
    res = []
    current = root
    while stack or current:
        # 将所有左节点入栈
        while current:
            stack.append(current)
            current = current.left
        # 弹出栈顶元素并访问
        current = stack.pop()
        res.append(current.value)
        current = current.right
    return res

3、后序遍历代码 

后序遍历需要用到辅助栈,第一个栈用于模拟遍历过程。第二个栈用于存储结果。实现过程如下:

  • 当遍历的栈非空时,弹出栈顶元素,并将栈顶元素压入存储栈
  • 左节点和右节点先后进入遍历栈
  • 最后输出存储栈
def postorder_traversal_iterative(root):
    if not root:
        return []
    
    stack1 = [root]  # 用于模拟遍历
    stack2 = []  # 用于存储结果
    result = []
    
    while stack1:
        node = stack1.pop()  # 弹出栈顶节点
        stack2.append(node)  # 将节点压入第二个栈
        
        # 左子节点先入栈
        if node.left:
            stack1.append(node.left)
        # 右子节点后入栈
        if node.right:
            stack1.append(node.right)
    
    # 从第二个栈中弹出节点,即为后序遍历结果
    while stack2:
        result.append(stack2.pop().value)
    
    return result

4、递归遍历

递归法比较简单,直接按照顺序写代码就可以了

# 前序遍历
def preorder_traversal(root):
    if root is None:
        return []
    return [root.value] + preorder_traversal(root.left) + preorder_traversal(root.right)


# 中序遍历
def inorder_traversal(root):
    if root is None:
        return []
    return inorder_traversal(root.left) + [root.value] + inorder_traversal(root.right)


# 后序遍历
def postorder_traversal(root):
    if root is None:
        return []
    return postorder_traversal(root.left) + postorder_traversal(root.right) + [root.value]

5、最后进行测试

# 定义二叉树节点类
class TreeNode:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

if __name__ == "__main__":
    # 构建二叉树
    root = TreeNode(1)
    root.left = TreeNode(2)
    root.right = TreeNode(3)
    root.left.left = TreeNode(4)
    root.left.right = TreeNode(5)

    # 测试遍历函数
    print("前序遍历:", preorder_traversal(root))  # 输出: [1, 2, 4, 5, 3]
    print("中序遍历:", inorder_traversal(root))  # 输出: [4, 2, 5, 1, 3]
    print("后序遍历:", postorder_traversal(root))  # 输出: [4, 5, 2, 3, 1]

    # 测试非递归
    print("非递归前序遍历:", preorder_traversal_iterative(root))  # 输出: [1, 2, 4, 5, 3]
    print("非递归中序遍历:", inorder_traversal_iterative(root))  # 输出: [4, 2, 5, 1, 3]
    print("非递归后序遍历:", postorder_traversal_iterative(root))  # 输出: [4, 5, 2, 3, 1]


都看到这里了,给个小心心♥呗~ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/973778.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot(七):Swagger 接口文档

1. Swagger 简介 1.1 Swagger 是什么? Swagger 是一款 RESTful 风格的接口文档在线自动生成 功能测试功能软件。Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。目标是使客户端和文件系统作为服务器以同样的…

STM32+Proteus+DS18B20数码管仿真实验

1. 实验准备 硬件方面: 了解 STM32 单片机的基本原理和使用方法,本实验可选用常见的 STM32F103 系列。熟悉 DS18B20 温度传感器的工作原理和通信协议(单总线协议)。数码管可选用共阴极或共阳极数码管,用于显示温度值。…

【进程与线程】Linux 线程、同步以及互斥

每个用户进程有自己的地址空间。 线程是操作系统与多线程编程的基础知识。 系统为每个用户进程创建一个 task_struct 来描述该进程:该结构体中包含了一个指针指向该进程的虚拟地址空间映射表: 实际上 task_struct 和地址空间映射表一起用来表示一个进程…

day16_推荐系统和总结

文章目录 day16_推荐系统和总结一、推荐实现1、基于流行度推荐(掌握)1.1 近期热门商品推荐1.2 个人热门商品推荐 2、基于隐语义模型的协同过滤推荐(了解)2.1 ALS算法介绍2.2 推荐代码 3、基于物品的协同过滤推荐(了解&…

深度解析应用层协议-----HTTP与MQTT(涵盖Paho库)

HTTP协议概述 1.1 HTTP的基本概念 HTTP是一种应用层协议,使用TCP作为传输层协议,默认端口是80,基于请求和响应的方式,即客户端发起请求,服务器响应请求并返回数据(HTML,JSON)。在H…

redis的应用,缓存,分布式锁

1.应用 1.1可以用作缓存 作用:提交数据的查询效率,减少对数据库的访问频率 什么数据适合放入缓存 1.查询频率高,修改频率低 2.对安全系数比较低 如何实现 Service public class DeptServer {Autowiredprivate DeptMapper deptMapper;Auto…

Ubuntu22.04 - etcd的安装和使用

目录 介绍安装Etcd安装etcd的客户端使用 介绍 Etcd 是一个 golang 编写的分布式、高可用的一致性键值存储系统,用于配置共享和服务发现等。它使用 Raft 一致性算法来保持集群数据的一致性,且客户端通过长连接watch 功能,能够及时收到数据变化…

对学习编程语言的一些理解

目录 一、代码运行的过程 二、跨平台的实现 1)C/C 2)C# 3)Java 三、总结 一、代码运行的过程 开发程序无论使用何种编程语言,至少都需要经历编码、编译、连接和运行这么4个过程,C语言是这样,Java语言…

【知识】深度学习中,应该先zero_grad还是先backward?

转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 目录 抛出问题 各大GPT的回答 ChatGPT-4o ChatGPT-o3-mini-high Kimi-长思考 Deepseek-R1 Grok3 Pytorch官方教程中 抛出问题 以下哪种方式是…

kafka消费能力压测:使用官方工具

背景 在之前的业务场景中,我们发现Kafka的实际消费能力远低于预期。尽管我们使用了kafka-go组件并进行了相关测试,测试情况见《kafka-go:性能测试》这篇文章。但并未能准确找出消费能力低下的原因。 我们曾怀疑这可能是由我的电脑网络带宽问题或Kafka部…

蓝桥云客 路径之谜

11.路径之谜 - 蓝桥云课 路径之谜 题目描述 小明冒充X星球的骑士,进入了一个奇怪的城堡。 城堡里边什么都没有,只有方形石头铺成的地面。 假设城堡地面是nn个方格。如下图所示。 按习俗,骑士要从西北角走到东南角。可以横向或纵向移动&…

Oracle 深入理解Lock和Latch ,解析访问数据块全流程

Oracle 锁机制介绍 根据保护对象的不同,单实例Oracle数据库锁可以分为以下几大类: DML lock(data locks,数据锁):用于保护数据的完整性; DDL lock(dictionary locks,字典…

Jenkins 环境搭建---基于 Docker

前期准备 提前安装jdk、maven、nodeJs(如果需要的话) 创建 jenkins 环境目录,用来当做挂载卷 /data/jenkins/ 一:拉取 Jenkins 镜像 docker pull jenkins/jenkins:lts 二:设置 Jenkins挂载目录 mkdir -p ~/jen…

DOS网络安全

ping -t 不间断地ping目标主机,直到用户用ctrlc键强行终止。经常用来排除网络故障 -l 定制ping信息包的容量,最大上限是65500字节 -n 向远程主机发送的数据 包个数,默认是4。 语法: ping 参数 IP地址 netstat -a 显示所有连接…

QML Component 与 Loader 结合动态加载组件

在实际项目中,有时候我们写好一个组件,但不是立即加载出来,而是触发某些条件后才动态的加载显示出来,当处理完某些操作后,再次将其关闭掉; 这样的需求,可以使用 Component 包裹着组件&#xff…

在 Mac ARM 架构的 macOS 系统上启用 F1 键作为 Snipaste 的截屏快捷键

在 Mac ARM 架构的 macOS 系统上启用 F1 键作为 Snipaste 的截屏快捷键,主要涉及到两个方面:确保 F1 键作为标准功能键工作 和 在 Snipaste 中设置 F1 为快捷键。 因为 Mac 默认情况下,F1-F12 键通常用作控制屏幕亮度、音量等系统功能的快捷键…

vue3学习1

vite是新的官方构建工具,构建速度比webpack更快 vue项目的入口文件是index.html,一般在这里引入src/main.js,并且设置好容器#app App.vue放的是根组件,components里放分支组件 vue组件中写三种标签,template & s…

istio实现灰度发布,A/B发布, Kiali网格可视化(二)

代码发布是软件开发生命周期中的一个重要环节,确保新功能和修复能够顺利上线。以下是几种常见的代码发布流程。在学习灰度发布之前。我们首先回忆下代码发布常用的几种方法。 A/B(蓝绿)发布: 蓝绿部署是一种通过维护两套独立的环…

MySQL日志undo log、redo log和binlog详解

MySQL 日志:undo log、redo log、binlog 有什么用? 一、前言 在MySQL数据库中,undo log、redo log和binlog这三种日志扮演着至关重要的角色,它们各自承担着不同的功能,共同保障了数据库的正常运行和数据的完整性。了解…

DeepSeek接入Siri(已升级支持苹果手表)完整版硅基流动DeepSeek-R1部署

DeepSeek接入Siri(已升级支持苹果手表)完整版硅基流动DeepSeek-R1部署 **DeepSeek** 是一款专注于深度学习和人工智能的工具或平台,通常与人工智能、机器学习、自动化分析等领域有关。它的主要功能可能包括:深度学习模型搜索&…