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

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

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

相关文章

游戏引擎学习第25天

Git: https://gitee.com/mrxiao_com/2d_game 今天的计划 总结和复述: 这段时间的工作已经接近尾声,虽然每次编程的时间只有一个小时,但每一天的进展都带来不少收获。尽管看起来似乎花费了很多时间,实际上这些日积月累的时间并未…

【C++】深入优化计算题目分析与实现

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯第一题:圆的计算我的代码实现代码分析改进建议改进代码 老师的代码实现代码分析可以改进的地方改进代码 💯第二题:对齐输出我的代码实现…

Kafka配置SASL/PLAINTEXT安全认证

1、下载安装 Kafka下载地址:Apache Kafka 下载文件 wget https://downloads.apache.org/kafka/3.8.0/kafka_2.12-3.8.0.tgz 文件解压缩 tar -zxvf kafka_2.12-3.8.0.tgz 进入目录 cd kafka_2.12-3.8.0 2、Zookeeper 配置 2.1、修改 Zookeeper 配置文件 con…

go并发设计模式runner模式

go并发设计模式runner模式 真正运行的程序不可能是单线程运行的,go语言中最值得骄傲的就是CSP模型了,可以说go语言是CSP模型的实现。 假设现在有一个程序需要实现,这个程序有以下要求: 程序可以在分配的时间内完成工作&#xff0…

机器学习周志华学习笔记-第13章<半监督学习>

机器学习周志华学习笔记-第13章<半监督学习> 卷王,请看目录 13半监督学习13.1 生成式方法13.2 半监督SVM13.3 基于分歧的方法13.4 半监督聚类 13半监督学习 前面我们一直围绕的都是监督学习与无监督学习,监督学习指的是训练样本包…

DevOps工程技术价值流:GitLab源码管理与提交流水线实践

在当今快速迭代的软件开发环境中,DevOps(开发运维一体化)已经成为提升软件交付效率和质量的关键。而GitLab,作为一个全面的开源DevOps平台,不仅提供了强大的版本控制功能,还集成了持续集成/持续交付(CI/CD)…

Android笔记【12】脚手架Scaffold和导航Navigation

一、前言 学习课程时,对于自己不懂的点的记录。 对于cy老师第二节课总结。 二、内容 1、PPT介绍scaffold 2、开始代码实操 先新建一个screen包,写一个Homescreen函数,包括四个页面。 再新建一个compenent包,写一个displayText…

动态规划-----路径问题

动态规划-----路径问题 下降最小路径和1:状态表示2:状态转移方程3 初始化4 填表顺序5 返回值6 代码实现 总结: 下降最小路径和 1:状态表示 假设:用dp[i][j]表示:到达[i,j]的最小路径 2:状态转…

C_字符串的一些函数

1.字符串输入函数 scanf("%s",数组名)&#xff1b; gets(数组名)&#xff1b; 区别&#xff1a; scanf(“%s”,数组名); 把空格识别为输入结束 #include <stdio.h>int main() {char a[10];printf("输入&#xff1a;");scanf("%s",a)…

【数据事务】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

Zookeeper集群数据是如何同步的?

大家好&#xff0c;我是锋哥。今天分享关于【Zookeeper集群数据是如何同步的?】面试题。希望对大家有帮助&#xff1b; Zookeeper集群数据是如何同步的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper集群中的数据同步是通过一种称为ZAB&#xff08;Zo…

MySQL需掌握到何种程度?才能胜任工作

大家好&#xff0c;我是袁庭新。星友问&#xff1a;MySQL需要学到什么程度&#xff1f;才能胜任日常的软件开发工作呢&#xff01;以下是一些建议的学习目标和程度&#xff0c;这些目标旨在帮助你在工作中高效地使用MySQL。 数据库的基本概念、MySQL的安装及配置、SQL的概念、S…

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. 无语义…

Qt 2D绘图之三:绘制文字、路径、图像、复合模式

参考文章链接: Qt 2D绘图之三:绘制文字、路径、图像、复合模式 绘制文字 除了绘制图形以外,还可以使用QPainter::darwText()函数来绘制文字,也可以使用QPainter::setFont()设置文字所使用的字体,使用QPainter::fontInfo()函数可以获取字体的信息,它返回QFontInfo类对象…

java调用ai模型:使用国产通义千问完成基于知识库的问答

整体介绍&#xff1a; 基于RAG&#xff08;Retrieval-Augmented Generation&#xff09;技术&#xff0c;可以实现一个高效的Java智能问答客服机器人。核心思路是将预先准备的问答QA文档&#xff08;例如Word格式文件&#xff09;导入系统&#xff0c;通过数据清洗、向量化处理…

Java 基于Spring AI RAG组件做AI智能问答_rag检索增强_AI智能问答

基于RAG技术构建高效Java智能问答客服机器人 基于RAG&#xff08;Retrieval-Augmented Generation&#xff09;技术&#xff0c;可以构建高效的Java智能问答客服机器人。首先&#xff0c;通过向量化处理将Word格式的问答QA文档转换为机器可理解的形式&#xff0c;并存储于Vect…

顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测(Maltab)

顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测&#xff08;Maltab&#xff09; 目录 顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测&#xff08;Maltab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实…

Redis+Caffeine 多级缓存数据一致性解决方案

RedisCaffeine 多级缓存数据一致性解决方案 背景 之前写过一篇文章RedisCaffeine 实现两级缓存实战&#xff0c;文章提到了两级缓存RedisCaffeine可以解决缓存雪等问题也可以提高接口的性能&#xff0c;但是可能会出现缓存一致性问题。如果数据频繁的变更&#xff0c;可能会导…

单片机学习笔记 12. 定时/计数器_定时

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…

6.824/6.5840(2024)环境配置wsl2+vscode

本文是经过笔者实践得出的最速の环境配置 首先&#xff0c;安装wsl2和vscode 具体步骤参见Mit6.s081环境配置踩坑之旅WSL2VScode_mit6s081-CSDN博客 接下来开始为Ubuntu(笔者使用的版本依然是20.04)配置go的相关环境 1、更新Ubuntu的软件包 sudo apt-get install build-es…