二叉树算法之二叉树遍历(前序、中序、后序、层次遍历)

二叉树遍历是指按照某种顺序访问二叉树的所有节点。常见的二叉树遍历方式包括前序遍历(Preorder Traversal)、中序遍历(Inorder Traversal)、后序遍历(Postorder Traversal)和层次遍历(Level-order Traversal)。不同的遍历方式有不同的应用场景,下面我们详细介绍这几种遍历方式及其实现。

1. 前序遍历(Preorder Traversal)

在前序遍历中,按照“根节点 -> 左子树 -> 右子树”的顺序遍历二叉树的节点。即:首先访问根节点,然后递归地遍历左子树,最后递归地遍历右子树。

前序遍历的顺序:
当前节点 -> 左子节点 -> 右子节点

前序遍历的递归实现:

// 定义二叉树节点
class TreeNode {int val;TreeNode left, right;TreeNode(int val) {this.val = val;this.left = this.right = null;}
}public class BinaryTreeTraversal {// 前序遍历 - 递归实现public void preorder(TreeNode root) {if (root == null) {return;}System.out.print(root.val + " ");  // 访问根节点preorder(root.left);  // 递归遍历左子树preorder(root.right);  // 递归遍历右子树}
}
前序遍历的非递归实现:

可以用栈模拟递归的过程,先访问根节点,然后将右子树和左子树依次压栈,确保左子树先被遍历。

import java.util.Stack;public class BinaryTreeTraversal {// 前序遍历 - 非递归实现public void preorderIterative(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();System.out.print(node.val + " ");  // 访问根节点if (node.right != null) {stack.push(node.right);  // 右子树入栈}if (node.left != null) {stack.push(node.left);  // 左子树入栈}}}
}

2. 中序遍历(Inorder Traversal)

在中序遍历中,按照“左子树 -> 根节点 -> 右子树”的顺序遍历二叉树的节点。即:首先递归地遍历左子树,然后访问根节点,最后递归地遍历右子树。

中序遍历的顺序:
左子节点 -> 当前节点 -> 右子节点

中序遍历的递归实现:

public class BinaryTreeTraversal {// 中序遍历 - 递归实现public void inorder(TreeNode root) {if (root == null) {return;}inorder(root.left);  // 递归遍历左子树System.out.print(root.val + " ");  // 访问根节点inorder(root.right);  // 递归遍历右子树}
}
中序遍历的非递归实现:

同样可以使用栈来实现,先遍历到最左边的节点,然后逐步回溯访问根节点,最后遍历右子树。

import java.util.Stack;public class BinaryTreeTraversal {// 中序遍历 - 非递归实现public void inorderIterative(TreeNode root) {Stack<TreeNode> stack = new Stack<>();TreeNode curr = root;while (curr != null || !stack.isEmpty()) {while (curr != null) {stack.push(curr);  // 左子树入栈curr = curr.left;}curr = stack.pop();  // 弹出栈顶节点并访问System.out.print(curr.val + " ");curr = curr.right;  // 遍历右子树}}
}

3. 后序遍历(Postorder Traversal)

在后序遍历中,按照“左子树 -> 右子树 -> 根节点”的顺序遍历二叉树的节点。即:首先递归地遍历左子树,然后递归地遍历右子树,最后访问根节点。

后序遍历的顺序:
左子节点 -> 右子节点 -> 当前节点

后序遍历的递归实现:

public class BinaryTreeTraversal {// 后序遍历 - 递归实现public void postorder(TreeNode root) {if (root == null) {return;}postorder(root.left);  // 递归遍历左子树postorder(root.right);  // 递归遍历右子树System.out.print(root.val + " ");  // 访问根节点}
}
后序遍历的非递归实现:

后序遍历较复杂,需要两个栈,一个用于模拟递归,另一个用于输出结果。

import java.util.Stack;public class BinaryTreeTraversal {// 后序遍历 - 非递归实现public void postorderIterative(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();Stack<TreeNode> output = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();output.push(node);if (node.left != null) {stack.push(node.left);  // 左子树入栈}if (node.right != null) {stack.push(node.right);  // 右子树入栈}}while (!output.isEmpty()) {System.out.print(output.pop().val + " ");  // 输出结果}}
}

4. 层次遍历(Level-order Traversal)

层次遍历是按照每一层节点的顺序从上到下,从左到右依次遍历二叉树的节点。可以通过队列实现,每次从队列中取出一个节点,然后将其左右子节点依次加入队列。

层次遍历的顺序:
按照从上到下、从左到右的层次顺序遍历节点

层次遍历的实现:

import java.util.LinkedList;
import java.util.Queue;public class BinaryTreeTraversal {// 层次遍历 - 使用队列实现public void levelOrder(TreeNode root) {if (root == null) {return;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {TreeNode node = queue.poll();System.out.print(node.val + " ");  // 访问当前节点if (node.left != null) {queue.offer(node.left);  // 左子节点入队}if (node.right != null) {queue.offer(node.right);  // 右子节点入队}}}
}

四种遍历的总结

  • 前序遍历(Preorder Traversal):根 -> 左 -> 右,通常用于复制树。
  • 中序遍历(Inorder Traversal):左 -> 根 -> 右,通常用于输出升序排序(对二叉搜索树)。
  • 后序遍历(Postorder Traversal):左 -> 右 -> 根,通常用于删除树或者计算子树的大小。
  • 层次遍历(Level-order Traversal):按层次顺序遍历,常用于广度优先搜索。

这些遍历方式各有特点,应用于不同的场景。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

stm32 bootloader写法

bootloader写法&#xff1a; 假设app的起始地址&#xff1a;0x08020000&#xff0c;则bootloader的范围是0x0800,0000~0x0801,FFFF。 #define APP_ADDR 0x08020000 // 应用程序首地址定义 typedef void (*APP_FUNC)(void); // 函数指针类型定义 /*main函数中调用rum_app&#x…

【从零开始的LeetCode-算法】504. 七进制数

给定一个整数 num&#xff0c;将其转化为 7 进制&#xff0c;并以字符串形式输出。 示例 1: 输入: num 100 输出: "202"示例 2: 输入: num -7 输出: "-10"提示&#xff1a; -107 < num < 107 我的解答 class Solution {public String convertT…

大数据存储计算平台EasyMR:大数据集群动态扩缩容,快速提升集群服务能力

在当今的数据驱动时代&#xff0c;组织面临着数据量的爆炸性增长。为了有效管理和存储这些数据&#xff0c;许多组织依赖于 Hadoop 这样的分布式存储系统。Hadoop 集群通过在多个节点上存储数据的冗余副本&#xff0c;提供了高可靠性和可扩展性。然而&#xff0c;随着数据量的不…

ChatGPT国内中文版镜像网站整理合集(2024/10/06)

一、GPT中文镜像站 ① yixiaai.com 支持GPT4、4o以及o1&#xff0c;支持MJ绘画 ② chat.lify.vip 支持通用全模型&#xff0c;支持文件读取、插件、绘画、AIPPT ③ AI Chat 支持GPT3.5/4&#xff0c;4o以及MJ绘画 1. 什么是镜像站 镜像站&#xff08;Mirror Site&#xff…

Spring Boot在线考试系统:JavaWeb技术的应用案例

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

英飞达医学影像存档与通信系统 WebUserLogin.asmx 信息泄露漏洞复现

0x01 产品简介 英飞达医学影像存档与通信系统 Picture Archiving and Communication System,它是应用在医院影像科室的系统,主要的任务就是把日常产生的各种医学影像(包括核磁,CT,超声,各种X光机,各种红外仪、显微仪等设备产生的图像)通过各种接口(模拟,DICOM,网络…

概率 随机变量以及分布

一、基础定义及分类 1、随机变量 随机变量是一个从样本空间&#xff08;所有可能结果的集合&#xff09;到实数集的函数。&#xff08;随机变量的值可以是离散的&#xff0c;也可以是连续的。 &#xff09; 事件可以定义为随机变量取特定值的集合。 2、离散型随机变量 随机变…

OpenCV高级图形用户界面(17)设置一个已经创建的滚动条的最小值函数setTrackbarMin()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::setTrackbarMin 这个函数的作用就是设置指定窗口中轨迹条的最小位置。这使得开发者能够在程序运行时动态地调整轨迹条的范围&#xff0c;而不…

Leetcode—1242. 多线程网页爬虫【中等】Plus(多线程)

2024每日刷题&#xff08;187&#xff09; Leetcode—1242. 多线程网页爬虫 实现代码 /*** // This is the HtmlParsers API interface.* // You should not implement it, or speculate about its implementation* class HtmlParser {* public:* vector<string>…

Go程序的一生——Go如何跑起来的?

引入编译链接概述 编译过程 词法分析语法分析语义分析中间代码生成目标代码生成与优化链接过程Go 程序启动GoRoot 和 GoPathGo 命令详解 go buildgo installgo run总结参考资料 引入 我们从一个 Hello World 的例子开始&#xff1a; package mainimport "fmt"func…

PROFINET开发EtherNet/IP开发Vline板卡在称重设备行业的应用

本次分享的&#xff0c;是我们VlinePROFINET开发EtherNet/IP开发嵌入式板卡在称重行业的典型应用。 应用背景 在现代科技高度发达的时代&#xff0c;无论是科学研究、医疗诊断、制药生产还是工业制造&#xff0c;准确的测量和称重都是保证质量和效率的关键。 随着新项目实施…

【BGA布局布线-熬夜加班整理】

BGA CHIP PLACEMENT AND ROUTING RULE BGA 是 PCB 上常用的组件&#xff0c;通常 CPU、NORTH BRIDGE、SOUTH BRIDGE、 AGP CHIP、CARD BUS CHIP…等&#xff0c;大多是以 bga 的型式包装&#xff0c;简言之&#xff0c;80&#xfe6a;的 高频信号及特殊信号将会由这类型的 pac…

自动化测试与敏捷开发的重要性

敏捷开发与自动化测试是现代软件开发中两个至关重要的实践&#xff0c;它们相互补充&#xff0c;共同促进了软件质量和开发效率的提升。 敏捷开发的重要性 敏捷开发是一种以人为核心、迭代、循序渐进的软件开发方法。它强调以下几个核心价值观和原则&#xff1a; 个体和交互…

服务器技术研究分析:存储从HBM到CXL

服务器变革&#xff1a;存储从HBM到CXL 在《从云到端&#xff0c;AI产业的新范式&#xff08;2024&#xff09;》中揭示&#xff0c;传统服务器价格低至1万美金&#xff0c;而配备8张H100算力卡的DGX H100AI服务器价值高达40万美金&#xff08;约300万人民币&#xff09;。 从供…

jmeter使用文档

文章目录 一、安装使用1、下载2、bin/jmeter.properties介绍 二、windows使用1、微调&#xff08;1&#xff09;界面样式&#xff08;2&#xff09;修改语言 2、简单使用3、各组件详解&#xff08;1&#xff09;CSV 数据文件配置&#xff08;2&#xff09;BeanShell取样器 三、…

Golang | Leetcode Golang题解之第478题在圆内随机生成点

题目&#xff1a; 题解&#xff1a; type Solution struct {radius, xCenter, yCenter float64 }func Constructor(radius, xCenter, yCenter float64) Solution {return Solution{radius, xCenter, yCenter} }func (s *Solution) RandPoint() []float64 {r : math.Sqrt(rand.…

C++之设计原则

在C中&#xff0c;设计原则是一套指导软件开发过程中决策和设计模式的准则&#xff0c;旨在提高软件的可维护性、可扩展性、灵活性和可靠性。 以下是几种核心设计原则&#xff1a; 1.单一职责 功能单一&#xff0c;方便组合和复用。 图示&#xff1a; 应用场景&#xff1a;…

【godot游戏引擎学习笔记】初识界面

个人笔记&#xff0c;学习自B站视频BV1ut42177r8 目录 渲染器的选择 Forward 移动 兼容 编辑器页面 浏览场景&#xff08;左上角&#xff09; 文件浏览器&#xff08;左下角&#xff09; 属性检查器&#xff08;右侧&#xff09; 场景编辑器&#xff08;中间&#x…

electron本地OCR实现

使用tesseract.js - npm (npmjs.com) 官方demo&#xff1a;GitHub - Balearica/tesseract.js-electron: An example to use tesseract.js in electron 目录结构&#xff1a; // 引入 <script type"module" src"./ocr/tesseract.js"></script>…

如何设置 GitLab 密码过期时间?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 60天专业…