c语言通过前序遍历构建二叉树

前言:

        在链式二叉树中,我们一般都是通过一个建立好的二叉树从而算出他的前序遍历,那么如何通过一个前序遍历来创建一个二叉树呢,本文将详细解读前序遍历每一个步骤是如何创建二叉树的。

1、分析前序遍历,构建出二叉树

        现有前序遍历:abc##de#g##f###,其中‘#’号表示NULL。由于前序遍历的顺序为:根结点-左子树-右子树,因此该前序遍历的第一个字符表示的是整个树的根结点,既字符a是根结点。下一个字符按照前序遍历的顺序应该是根结点a的左子树也就是b为a的左子树:


        这时候根(a)-左子树(b)的顺序已经走完,下一个理应是右子树,但是这时候b被看成了一个根结点,因此顺序又回到了根结点(b)-左子树-右子树,该前序遍历的下一个字符c被当成b的左子树:


        此时根(b)-左子树(c)顺序已经走完,按理来说应该到根(b)-左子树(c)-右子树(#),但是情况和上面一样,把c看成了根结点,则该前序序列的下一个字符‘#’号是c的左子树。但是‘#’号表示的是NULL,因此走到‘#'号时不会把’#‘当成一个根结点来看待了,所以会走完根结点c的顺序,既:根(c)-左子树(#)-右子树(#),如下图:


        现在终于完整的走完了一次前序遍历的顺序,接着就是往上”收回“,因为结点c下面两个孩子结点都为NULL,因此不会再往下走。结点c遍历结束后,表示的是b的左子树完成, 那么接着刚刚结点b的前序遍历:此时根(b)-左子树(c),接下来应该是根结点b的右子树,因此把该序列的下一个字符d看成是b的右子树:


        现在虽然根结点b完成了他的树,但是结点d的两个孩子结点也是需要填写的,逻辑也是前序遍历的逻辑:根结点(d)-左子树-右子树,该序列的下一个字符看成d的左子树:


        此时,结点e不是NULL,他还是一个结点,因此他也会被当成根结点,继续属于他的顺序,则下一个字符’#‘号是e的左子树,’#‘号不会被当成根结点,因此g被看成是e的右子树:


        结点g的逻辑同结点e一样,他也被看成一个结点,因此也有属于g的孩子结点,则该序列的后两个’#‘号是g的左右孩子:


        此时g结点的孩子结点都是NULL,代码g作为根结点的前序顺序结束,这时候要进行”收回“,通过上图可以看到,d的右子树还没有进行遍历,因此”收回“至d的左子树处,遍历d的右子树:


        可以看到,d的右子树并不是NULL,是一个结点f,因此逻辑相同: 


        f的两个孩子结点都是NULL,表示f作为根结点的前序顺序完成,又表示根结点a的左子树全部完成,因此“收回”至根结点a的左子树处,接下来就是遍历根节点a的右子树,可以看到序列中只剩下一个’#‘号了,所以根结点a的右子树其实就是一个NULL:


2、代码实现及验证

        将以上思想转换成代码形式,并且用中序遍历打印该树,观察结果的正确性,前序遍历:abc##de#g##f###可以看成是字符串,因此用数组的形式将其存储。构建二叉树代码如下:

#include <stdio.h>
#include <stdlib.h>//创建树节点结构体
typedef int TreeDataType;//int类型重定义
typedef struct TreeNode
{TreeDataType data;struct TreeNode* left;struct TreeNode* right;
}TNode;//创建树节点
TNode* CreatTreeNode(int x)
{TNode* treenode = (TNode*)malloc(sizeof(TNode));if (treenode == NULL){perror("malloc");return NULL;}treenode->data = x;treenode->left = NULL;treenode->right = NULL;return treenode;//返回创建号的树节点地址
}//利用前序遍历构建树
TNode* CreatTree(char* arr, int* pi)
{if (arr[(*pi)] == '#')//当数组内遍历到#号,表示空,直接返回即可{(*pi)++;//遍历数组return NULL;}TNode* poi = CreatTreeNode(arr[(*pi)]);//走到此处表示遍历数组遇到的不是#,则创建结点(*pi)++;//遍历数组//递归思想poi->left = CreatTree(arr, pi);//将该结点看成根结点,去创建他的左子树poi->right = CreatTree(arr, pi);//将该结点看成根结点,去创建他的右子树return poi;//返回该结点的地址给到上一层结点,将他们相连(递归思想)
}//中序遍历
void InOrder(TNode* boot)
{if (boot == NULL){return;}InOrder(boot->left);//遍历左子树printf("%c ", boot->data);//打印该结点的值,既打印根节点的值InOrder(boot->right);//遍历右子树
}//主函数
int main() {char arr[100];//创建一个数组用于保存前序遍历,因此可以把前序遍历看成一个字符串scanf("%s", arr);int i = 0;//i为数组的下标,用于遍历数组TNode* root = CreatTree(arr, &i);//用前序遍历构建树InOrder(root);//中序遍历检查结果return 0;
}

        运行结果:

        从运行结果来看,中序遍历为:c b e g d f a,中序遍历的顺序为:左子树-根-右子树,根据上文构建出来的二叉树来进行验证该树的中序遍历是否为c b e g d f a:


        待到方框1中遍历结束后,表示b的左子树遍历完成,根据中序遍历的顺序,下一步就是遍历根结点也就是结点b,然后是结点b的右子树d:


        当遍历结点d时,会把结点d当作根结点,因此顺序重新由左子树-根-右子树开始,会先遍历e结点,当遍历到e的右子树g时,逻辑也一样会把g当作根结点从而重新开始遍历g结点:


        方框4中结束后,表示d的左子树遍历完成,根据中序遍历顺序,下一个是遍历根也就是根结点d,然后是遍历d的右子树f,遍历结点f道理也一样,把f当成根结点并从f的左子树开始遍历:


        方框6中结束后,表示根结点a的左子树全部遍历完毕,按照中序遍历顺序,左子树完成后下一个是根结点,因此遍历根结点a,最后是遍历a的右子树,a的右子树为空因此最终的顺序如下:

        从上图可以看到最后的顺序和代码执行后的中序遍历顺序是一样的,因此说明该代码确实可以通过前序遍历创建出二叉树。 

结语:

        以上就是关于如何通过前序遍历创建出一个二叉树,尽管这个二叉树很复杂,但是最终还是能够实现出来的,并且其中的每一步遍历都蕴含了递归的思想,细品则会发现更深层次的递归二叉树实现。希望通过以上步骤能够加深你对二叉树的理解(●'◡'●)。

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

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

相关文章

智慧垃圾分拣站:科技改变城市环境,创造更美好的未来

随着城市化进程的不断加快&#xff0c;垃圾处理问题日益凸显。为了更好地解决垃圾分类问题&#xff0c;越来越多的城市开始推广智慧垃圾分拣站&#xff0c;利用创新科技实现高效垃圾分类处理。 山海鲸使用三维建模技术&#xff0c;建立了一个智慧垃圾分拣站数字孪生模型&#x…

外包干了5个月,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

每天一点python——day81

#每天一点Python——81 #递归函数&#xff1a; 递归函数&#xff1a; 一个函数在该函数体内调用了该函数本身&#xff0c;这个函数称为递归函数 【释&#xff1a;我自己调用自己的函数】 递归函数的组成部分&#xff1a; 递归调用与递归终止条件。 【一定有一个跳出循环的终止条…

解决WPS拖动整行的操作

如上图&#xff0c;想要把第4行的整行内容&#xff0c;平移到第1行。 1.选中第4行的整行 2.鼠标出现如图的样子时&#xff0c;按住鼠标左键&#xff0c;上移到第1行位置后&#xff0c;放开左键即可。

计算机网络:应用层(上篇)

文章目录 前言一、应用层协议原理1.网络应用的体系结构2.进程通信 二、Web与HTTP1.HTTP概况2.HTTP连接3.HTTP请求报文4.用户-服务器状态&#xff1a;cookies5.Web缓存&#xff08;代理服务器&#xff09; 三、FTP&#xff1a;文件传输协议1.FTP&#xff1a;控制连接与数据连接分…

watch监听中重复触发如何解决?

在实际开发工程中通过获取后端数据监听判断数组中长度是否大于0从而调用其他的方法&#xff0c;但是如果data域中的数据出现变化的话&#xff0c;就会导致监听中的方法重复调用&#xff0c;导致一些不必要的bug&#xff0c;例如&#xff1a; 原理&#xff1a; watch监听的数据…

Diffusion:通过扩散和逆扩散过程生成图像的生成式模型

在当今人工智能大火的时代&#xff0c;AIGC 可以帮助用户完成各种任务。作为 AIGC 主流模型的 DDPM&#xff0c;也时常在各种论文中被提起。DDPM 本质就是一种扩散模型&#xff0c;可以用来生成图片或者为图片去噪。 扩散模型定义了一个扩散的马尔科夫过程&#xff0c;每一步逐…

视频监控平台EasyCVR多场景应用,AI视频分析技术助力行业升级转型

传统的视频监控系统建设&#xff0c;经常存在各方面的因素制约&#xff0c;造成管理机制不健全、统筹规划不到位、联网共享不规范&#xff0c;形成“信息孤岛”、“数据烟囱”。在监控系统的建设中缺乏统一规划&#xff0c;标准不统一、视频图像信息利用率低等问题日益突出。随…

手动将jar包导入本地Maven仓库

1、进入存放jar包的目录&#xff0c;可以先放进仓库底下 2、cmd回车 3、执行命令&#xff0c;看到BUILD SUCCESS就是成功了 -DgroupId、-DartifactId、-Dversion、-Dfile记得换成自己对应的 mvn install:install-file -DgroupIdcom.github.03 -DartifactIdonvif -Dversion1.0.7…

微信小程序自定义tabber凸起

一、实现效果 二、下载地址 下载地址 源码有错自己修改一下就行

网站优化SEO文章采集组合方法

为了在激烈的网络竞争中脱颖而出&#xff0c;SEO专业人士不断寻求创新的方法和技术。其中&#xff0c;SEO文章采集后重组是一项备受关注的技术&#xff0c;通过巧妙地整合和重新组织已有的信息&#xff0c;以提升网站在搜索引擎中的排名和曝光度。 SEO文章采集是这一技术的第一…

Vue+Element-ui实例_在form中动态校验tag标签

1.开发需求 在日常开发中&#xff0c;我们会遇到form表单的动态添加和校验&#xff0c;当我们需要在动态添加的内容中再次动态使用输入框的时候&#xff0c;就会变得很繁琐&#xff0c;我在网上找了很多案例&#xff0c;没有符合自己需求的内容&#xff0c;只好闲暇时间自己搞…

Vue3依赖注入

适用场景 尤其针对一个变量需要从顶层组件开始透传&#xff0c;途径很多个子组件最后在第n代子组件使用的时候。对于这些途经的子组件而言&#xff0c;它们不但不使用而且完全不关心该变量具体是什么&#xff0c;只是作为一个传递工具罢了。这种情况下&#xff0c;使用依赖注入…

论文复现代码《基于自适应哈夫曼编码的密文可逆信息隐藏算法》调试版

前言 本文展示论文《基于自适应哈夫曼编码的密文可逆信息隐藏算法》的复现代码。代码块的结构如下&#xff1a; 其中&#xff0c;每个代码块都包含了测试该代码块的功能的主函数代码&#xff0c;使用时可放心运行&#xff0c;前提是你按照这个包结构把文件命名改好&#xff0c…

重载、重写、重定义的辨析

C重载、重写、重定义 重载、重写、重定义对比一、重载&#xff08;overload&#xff09;二、重写 / 覆盖&#xff08;override&#xff09;三、重定义 / 隐藏&#xff08;redefining&#xff09; * 为什么在虚函数中不能使用 static 关键字&#xff1f;动态绑定&#xff08;Dyn…

YOLOv5轻量化改进之MobileNetv3

目录 一、原理 二、代码 三、应用到YOLOv5 一、原理 我们提出了基于互补搜索技术和新颖架构设计相结合的下一代mobilenet。MobileNetV3通过硬件网络架构搜索(NAS)和NetAdapt算法的结合来调整到移动电话cpu,然后通过新的架构进步进行改进。本文开始探索自动搜索算法和网络设计…

map文件解析

Map文件内容分为以下五段&#xff1a; 1&#xff09;Section Cross References&#xff1a;模块、段(入口)交叉引用&#xff1b;(ASR编译生成的map文件没有输出该段信息) 2&#xff09;Removing Unused input sections from the image&#xff1a;移除未使用的模块&#xff1…

App测试中iOS和Android的差异

1、系统版本&#xff1a; iOS和Android系统版本的更新速度、使用人数比例以及功能的不同都可能导致应用程序在不同操作系统版本上的表现和兼容性存在区别。 例如&#xff0c;在iOS平台上&#xff0c;很多用户会更快地升级到最新版本的iOS系统&#xff0c;而在Android平台上&a…

智慧灯杆网关:引领城市智慧照明的未来

智慧灯杆网关&#xff0c;作为城市智慧照明系统的核心组件&#xff0c;正逐渐成为各大城市发展的关键所在。它的出现使得城市照明管理更加智能、高效&#xff0c;为未来城市的可持续发展奠定了坚实的基础。 智慧灯杆网关是一种集网络通信、数据处理、远程控制等功能于一体的设备…

一款适用于船载、化工园区、工厂的防水LoRa网关推荐

工业网关的实践应用场景非常广泛&#xff0c;比如&#xff1a;工业现场PLC、变频器、机器人等设备的远程维护&#xff1b;工程机械的远程维护和管理&#xff1b;车间设备与工艺系统的远程维护和管理&#xff1b;小区二次供水水泵的远程监测及控制&#xff1b;油气田和油井等现场…