当前位置: 首页 > news >正文

106.【C语言】数据结构之二叉树的三种递归遍历方式

目录

1.知识回顾

2.分析二叉树的三种遍历方式

1.总览

2.前序遍历

3.中序遍历

4.后序遍历

5.层序遍历

3.代码实现

1.准备工作

2.前序遍历函数PreOrder

测试结果

3.中序遍历函数InOrder

测试结果

4.后序遍历函数PostOrder

测试结果

4.底层分析


1.知识回顾

在99.【C语言】数据结构之二叉树的基本知识文章中提到:任何一棵树都由两部分构成:根和子树,子树又由根和子树构成

因此看见二叉树要本能地做出反应:拆成三部分:根,左子树和右子树,直到遇到空树(叶节点)则停止拆分

 7447cca743864287a76ebeab89df1c1c.png

2.分析二叉树的三种遍历方式

1.总览

前序遍历

中序遍历

后序遍历

层序遍历(要借助队列,本文暂时不讲其代码实现)

e7d5951f3821482fa7550385986249c9.png

下面三种遍历方式都基于上面这张图分析

2.前序遍历(也称先序遍历)

定义:按根-->左子树-->右子树的顺序遍历

遍历顺序:

1(根)-->2(根)-->3(根)-->NULL(3的左子树)-->NULL(3的右子树)-->NULL(2的右子树)-->4(根)-->5(根)-->NULL(5的左子树)-->NULL(5的右子树)-->6(根)-->NULL(6的左子树)-->NULL(6的右子树)

bd1f91734a014b38b19d7b5d86c7676d.png

备注:图中每个方框都代表一棵子树

3.中序遍历

定义:按左子树-->根-->右子树的顺序遍历

这里有一个易错点也是关键点:中序遍历中第一个访问的一定为空!!!!

虽然1的左节点为2,但不能访问2(即不可访问root->data),按中序遍历的定义,要先访问2的左子树;虽然2的左节点为3,但不能访问3,按中序遍历的定义,先访问3左子树;3的左子树为NULL,其没有子树,因此开始访问根(即3),再访问根的右子树NULL,再回归......

左子树访问完才能访问根

遍历顺序:NULL(3的左子树)-->3-->NULL(3的右子树)-->2(根)-->NULL(2的右子树)-->1(根)-->NULL(5的左子树)-->5(根)-->NULL(5的右子树)-->4(根)-->NULL(6的左子树)-->6(根)-->NULL(6的右子树)

dd6d7b25fa2e4f61b4164b0ffe7214d8.png

备注:图中每个方框都代表一棵子树  

4.后序遍历

定义:按左子树-->右子树-->根的顺序遍历

和中序遍历一样,也有一个易错点也是关键点:和中序遍历一样,先访问左子树,因此后序遍历中第一个访问的也一定为空!!!!

遍历顺序:NULL(3的左子树)-->NULL(3的右子树)-->3(根)-->NULL(2的右子树)-->2(根)-->NULL(5的左子树)-->NULL(5的右子树)-->5(根)-->NULL(6的左子树)-->NULL(6的右子树)-->6(根)-->4(根)-->1(根)

3c55dfd99ac743d0801bd39f6d065fec.png

备注:图中每个方框都代表一棵子树   

5.层序遍历

定义:按层的方式遍历(,设n为树的深度,h==1-->h==2-->h==3-->...-->h==n)

遍历顺序:1-->2-->4-->3-->5-->6

h==1为第一层,只有1;h==2为第二层,有2和4;h==3为第三层,有3,5和6;

3.代码实现

1.准备工作

用结构体去定义一个二叉树,其成员变量有:数值域data,结构体指针变量left和right,分别指向其对应的左子树和右子树(写入Tree.h)

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;

定义完二叉树后还要开辟空间函数BuyNode和建立树的函数(写入Tree.c)

BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc");return NULL;}node->data = x;node->left = NULL;node->right = NULL;return node;
}

建立指定的二叉树,见下图

 e7d5951f3821482fa7550385986249c9.png

BTNode* CreateTree()
{//写入各个节点的数据域BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);//设置left和right指针node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;//返回根节点的指针return node1;
}

递归返回的条件:遇到空树(NULL)

2.前序遍历函数PreOrder

按根-->左子树-->右子树的顺序遍历,

即printf("%d ",root->data);-->PreOrder(root->left);-->PreOrder(root->right);

void PreOrder(BTNode* root)
{//先判断是否为空树(叶节点的左节点和右节点均为空树)if (root == NULL){printf("NULL ");return;}//按根-->左子树-->右子树的顺序遍历printf("%d ",root->data);PreOrder(root->left);PreOrder(root->right);
}

注意:一定要先判断是否为空树(叶节点的左节点和右节点均为空树)

测试结果

mainc.c写入以下代码

#include "Tree.h"
int main()
{BTNode* root = CreateTree();PreOrder(root);return 0;
}

4281ea4b0863424e94e65923f055cf78.png

bd1f91734a014b38b19d7b5d86c7676d.png

和前面的图完全符合

3.中序遍历函数InOrder

:按左子树-->根-->右子树的顺序遍历,

即InOrder(root->left);-->printf("%d ", root->data);-->InOrder(root->right);

void InOrder(BTNode* root)
{//先判断是否为空树(叶节点的左节点和右节点均为空树)if (root == NULL){printf("NULL ");return;}//按左子树-->根-->右子树的顺序遍历InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}

注意:一定要先判断是否为空树(叶节点的左节点和右节点均为空树) 

测试结果

mainc.c写入以下代码

#include "Tree.h"
int main()
{BTNode* root = CreateTree();InOrder(root);return 0;
}

 f61598a6904e4cbda6aed0047cf9623a.png

dd6d7b25fa2e4f61b4164b0ffe7214d8.png 和前面的图完全符合

4.后序遍历函数PostOrder

按左子树-->右子树-->根的顺序遍历,

即PostOrder(root->left);-->PostOrder(root->right);-->printf("%d ", root->data);

void PostOrder(BTNode* root)
{//先判断是否为空树(叶节点的左节点和右节点均为空树)if (root == NULL){printf("NULL ");return;}//按左子树-->右子树-->根的顺序遍历PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}

注意:一定要先判断是否为空树(叶节点的左节点和右节点均为空树) 

测试结果

mainc.c写入以下代码

#include "Tree.h"
int main()
{BTNode* root = CreateTree();PostOrder(root);return 0;
}

ce1b1e00233142dd8d34a81c9d87d242.png

3c55dfd99ac743d0801bd39f6d065fec.png

和前面的图完全符合

4.底层分析

每调用一次PreOrder或InOrder或PostOrder函数就压入栈区,返回时出栈

在E41.【C语言】练习:斐波那契函数的空间复杂度的计算及函数调用分析文章中讲过了函数调用的堆栈分析,这里不再赘述

附一张PreOrder的调用图

e355fba3c180434e980b6c08259c252d.jpeg

附一张InOrder的调用图

9f446891de6c4ce1895580ce6945bc38.jpeg

相关文章:

106.【C语言】数据结构之二叉树的三种递归遍历方式

目录 1.知识回顾 2.分析二叉树的三种遍历方式 1.总览 2.前序遍历 3.中序遍历 4.后序遍历 5.层序遍历 3.代码实现 1.准备工作 2.前序遍历函数PreOrder 测试结果 3.中序遍历函数InOrder 测试结果 4.后序遍历函数PostOrder 测试结果 4.底层分析 1.知识回顾 在99.…...

qt QToolButton详解

1、概述 QToolButton是Qt框架中的一个控件,它继承自QAbstractButton。QToolButton通常用于工具栏(QToolBar)中,提供了一种快速访问命令或选项的方式。与普通的QPushButton按钮相比,QToolButton通常只显示一个图标而不…...

2024年大热,Access平替升级方案,也适合Excel用户

欢迎各位看官,您来了,就对了! 您多半是Access忠实粉丝,至少是excel用户,亦或是WPS用户吧。那就对了,今天的分享肯定对您有用。 本文1100字,阅读时长2分50秒! 现实总是不尽人意&am…...

探索Scala的模式匹配:身份证识别与等级判定!!! #Scala # scala #匹配模式

在Scala编程语言中,模式匹配是一个强大且表达力丰富的特性,它允许我们以声明式的方式处理多种情况。今天,我们将通过两个有趣的例子来展示Scala模式匹配的魅力:身份证号识别和等级判定。 1. 身份证号识别:定位你的家乡…...

python数据分析之爬虫基础:爬虫介绍以及urllib详解

前言 在数据分析中,爬虫有着很大作用,可以自动爬取网页中提取的大量的数据,比如从电商网站手机商品信息,为市场分析提供数据基础。也可以补充数据集、检测动态变化等一系列作用。可以说在数据分析中有着相当大的作用!…...

【星海随笔】syslinux

Ubuntu相关资料 https://www.pugetsystems.com/labs/hpc/ubuntu-22-04-server-autoinstall-iso/#Step_2_Unpack_files_and_partition_images_from_the_Ubuntu_2204_live_server_ISO https://launchpad.net/ubuntu/source/squashfs-tools/1:4.6.1-1build1 sudo tar -xf my_compu…...

力扣C语言刷题记录 (二)移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作: 更改…...

【Vue3】【Naive UI】<NAutoComplete>标签

【Vue3】【Naive UI】标签 <NAutoComplete> 是 Naive UI 库中的一个组件&#xff0c;用于实现自动完成或联想输入功能。 它允许用户在输入时看到与当前输入匹配的建议列表&#xff0c;从而帮助用户更快地填写表单字段。 这个组件通常用于搜索框、地址输入等场景&#xff…...

【Halcon】使用均值滤波出现假边怎么办?

在图像处理过程中,均值滤波是一种常见的平滑技术,用于减少图像中的噪声。然而,当应用于具有显著边缘或对比度变化的图像时,均值滤波可能会导致“假边”现象,即原本不存在的边缘在滤波后变得明显。以下是如何在Halcon中处理这一问题,并提供一个完整的示例代码。 示例背景…...

Flask+Minio实现断点续传技术教程

什么是MinIO MinIO是一个高性能的分布式对象存储服务&#xff0c;与Amazon S3 API兼容。它允许用户存储和检索任意规模的数据&#xff0c;非常适合于使用S3 API的应用程序。MinIO支持多租户存储&#xff0c;提供高可用性、高扩展性、强一致性和数据持久性。它还可以作为软件定义…...

JAVA设计模式,动态代理模式

动态代理&#xff08;Dynamic Proxy&#xff09;是Java中一种非常有用的设计模式。它允许在运行时创建一个实现了一组给定接口的新类。这种模式主要用于当需要为某个对象提供一个代理以控制对该对象的访问时。通过这种方式&#xff0c;可以添加额外的功能&#xff0c;如事务管理…...

HTML 快速上手

目录 一. HTML概念 二. HTML标签 1. 标题标签 2. 段落标签 3. 换行标签 4. 图片标签 5. 超链接标签 6. 表格标签 7. 表单标签 7.1 form 标签 7.2 input 标签 (1) 文本框 (2) 单选框 (3) 密码框 (4) 复选框 (5) 普通按钮 (6) 提交按钮 8. select标签 9. 无语义…...

【计算机视觉算法与应用】模板匹配、图像配准

目录 1. 基于灰度值的模板匹配 2. 基于相关性的模板匹配 3. 基于形状的模板匹配 4. 基于组件的模板识别 5. 基于形变的模板匹配 6. 基于描述符的模板匹配 7. 基于点的模板匹配 性能比较 模板匹配的算法实现需要结合具体需求和应用场景来选择方法。以下是基于 OpenCV 的…...

【Linux】设计文件系统(C实现)

要求&#xff1a; (1)可以实现下列几条命令 dir 列文件目录 create 创建文件 delete 删除文件 read 读文件 write 写文件 (2)列目录时要列出文件名、存取权限&#xff08;八进制&#xff09;、文件长度、时间&#xff08;创建时间&#xff0c;修改时间以及…...

详解Rust多线程编程

文章目录 多线程模型创建和管理线程自定义线程行为线程传递数据线程间通信线程池错误处理与线程Condvar(条件变量)无锁并发高性能并发库 Rust的多线程编程提供了一种安全、高效的方式来进行并发操作。Rust的并发性设计原则之一是确保线程安全&#xff0c;同时避免运行时的开销&…...

el-upload上传多个文件,一次请求,Django接收

1、:file-list"fileList" :on-change"handleChange" 将文件赋值到fileList 2、 :auto-upload"false" 手动触发上传 写个按钮点击执行这个 this.$refs.upload.submit(); 3、自己写上传&#xff0c;不会再触发上传成功或失败回调 4、 request.FI…...

Python实现网站资源批量下载【可转成exe程序运行】

Python实现网站资源批量下载【可转成exe程序运行】 背景介绍解决方案转为exe可执行程序简单点说详细了解下 声明 背景介绍 发现 宣讲家网 的PPT很好&#xff0c;作为学习资料使用很有价值&#xff0c;所以想下载网站的PPT课件到本地&#xff0c;但是由于网站限制&#xff0c;一…...

《JavaScript高级程序设计》读书笔记 20

感谢点赞、关注和收藏&#xff01; 原始值包装类型 为了方便操作原始值&#xff0c;ECMAScript 提供了 3 种特殊的引用类型&#xff1a;Boolean、Number 和 String。每当用到某个原始值的方法或属性时&#xff0c;后台都会创建一个相应原始包装类型的对象&#xff0c;从而暴露…...

ASP.NET Core项目中使用SqlSugar连接多个数据库的方式

之前学习ASP.NETCore及SqlSugar时都是只连接单个数据库处理数据&#xff0c;仅需在Program文件中添加ISqlSugarClient的单例即可&#xff08;如下代码所示&#xff09;。 builder.Services.AddSingleton<ISqlSugarClient>(s > {SqlSugarScope sqlSugar new SqlSugar…...

Java面试八股文(精选、纯手打)

全国内大厂Java面试高频题库 本小册内容涵盖&#xff1a;Java基础&#xff0c;JVM&#xff0c;多线程&#xff0c;数据库&#xff08;MySQL/Redis&#xff09;SSM&#xff0c;Dubbo&#xff0c;网络&#xff0c;MQ&#xff0c;Zookeeper&#xff0c;Netty&#xff0c;微服务&a…...

nRF52轻量级NFC Type 2标签驱动库解析

1. 项目概述aconno_nrf52_nfc是一个专为 Nordic Semiconductor nRF52 系列 SoC&#xff08;如 nRF52832、nRF52840&#xff09;设计的轻量级 NFC 标签驱动库。该库不依赖于 Nordic SDK 的完整 NFC 协议栈&#xff08;如nfc_t2t_lib或nfc_ndef&#xff09;&#xff0c;而是直接操…...

一文详解RPC,深入浅出从原理到主流框架

什么是RPC&#xff1f; RPC 全称 Remote Procedure Call&#xff0c;即远程过程调用。它的核心目标非常简单&#xff1a;让开发者调用远程机器上的函数/方法&#xff0c;就像调用本地函数一样简单&#xff0c;无需关注底层的网络连接、数据传输、序列化与反序列化等繁琐细节[1]…...

西交提出 OdysseyArena:让智能体真正“学会探索”的长程归纳推理基准

&#x1f4cc; 一句话总结&#xff1a; 本工作提出 OdysseyArena&#xff0c;一个面向长时程&#xff08;long-horizon&#xff09;、主动探索&#xff08;active&#xff09;、归纳学习&#xff08;inductive&#xff09;三大核心能力的交互式评测平台&#xff0c;系统性检验…...

OpenClaw调试技巧:Gemma-3-12b-it任务失败的根本原因分析

OpenClaw调试技巧&#xff1a;Gemma-3-12b-it任务失败的根本原因分析 1. 问题背景与现象描述 上周我在本地部署了Gemma-3-12b-it模型&#xff0c;准备用OpenClaw实现自动化周报生成。结果连续三次任务都在"分析本周工作内容"环节卡住&#xff0c;控制台只显示Task …...

智慧校园厂家怎么选?看懂这 5 个核心功能再决定不迟

✅作者简介&#xff1a;合肥自友科技 &#x1f4cc;核心产品&#xff1a;智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…...

Linux IO调度器详解与性能优化指南

1. Linux IO调度器概述作为一名长期从事Linux系统调优的工程师&#xff0c;我经常需要面对磁盘IO性能优化的问题。今天我想和大家深入探讨Linux内核中的四大IO调度算法&#xff0c;这些算法直接影响着系统的IO性能表现。现代计算机系统中&#xff0c;磁盘IO往往是性能瓶颈所在。…...

信通院:AI4SE行业现状调查报告 2026

这份信通院 2026 年 AI4SE 行业现状调查报告&#xff0c;核心是 AI 与软件工程深度融合进入规模化落地关键期&#xff0c;全流程提效显著&#xff0c;企业高度重视&#xff0c;但仍面临人才、成本等挑战&#xff0c;未来将走向自主编程、多智能体协同的新范式。一、调研概况有效…...

论文不同章节降AI策略不同:分章节精准处理的完整教程

论文不同章节降AI策略不同&#xff1a;分章节精准处理的完整教程 上周室友第一次用降AI工具&#xff0c;操作错了好几步&#xff0c;差点浪费机会。觉得有必要写一篇详细教程。 我用的是嘎嘎降AI&#xff08;www.aigcleaner.com&#xff09;&#xff0c;4.8元一篇&#xff0c…...

【2026年最新600套毕设项目分享】springboot校园二手交易系统(14339)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告/任务书&#xff09;远程调试控屏包运行一键启动项目&…...

IGBT驱动电路设计避坑指南:从选型到PCB布局的8个关键点

IGBT驱动电路设计避坑指南&#xff1a;从选型到PCB布局的8个关键点 在电力电子领域&#xff0c;IGBT驱动电路的设计质量直接决定了整个系统的可靠性和效率。我曾亲眼见过一个价值百万的变频器项目&#xff0c;因为驱动电阻选型不当导致批量烧毁&#xff0c;团队不得不连续加班三…...