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;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

pip安装、更新、卸载

目录 一、安装pip1. ensurepip2. get-pip.py2.1 下载get-pip.py2.2 pip安装2.3 检查pip版本 二、更新pip三、卸载pip 参考https://pip.pypa.io/en/stable/installation/ 一、安装pip 1. ensurepip python -m ensurepip --upgrade2. get-pip.py 2.1 下载get-pip.py 终端执行…

【算法题解】LeetCode169.多数元素——摩尔投票算法

169. 多数元素 题干 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1&#xff1a; 输入&#xff1a; nums [3,2,3] 输…

每天一点python——day81

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

解决WPS拖动整行的操作

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

程序员养生与延寿:关注健康,享受编码之旅

随着信息技术的迅猛发展&#xff0c;程序员的工作变得越来越重要。然而&#xff0c;长时间坐在电脑前&#xff0c;程序员们不可避免地面临着一些健康问题。他们的头发越来越少&#xff0c;眼镜度数越来越高&#xff0c;肚子上的赘肉也越来越多。为了更好地保持健康&#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监听的数据…

element-plus 上传组件 el-upload 直传第一次取不到数据

取不到数据是官方("element-plus": "^2.3.4") beforeData在beforeUploadPromise 之前导致异步设置:data 不生效文件传不上去的原因&#xff0c;改为http-request去处理就可以了。挺奇怪&#xff0c;之前用("element-plus": "^2.2.17")…

数组元素的删除

完成数组元素的移动功能&#xff1a;假设数组有n个元素&#xff0c;输入一个数x&#xff0c;把数组的第x个位置的元素删除了&#xff0c;后面的元素依次前进一个位置。 重复若干次这样的删除&#xff0c;得到最后的结果。 输入格式: 第一行包括一个整数n&#xff08;1<n&l…

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

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

blender导出相机参数

前言&#xff1a;在 Blender 的图形化界面中&#xff0c;没有直接的选项可以导出渲染图片的外参矩阵。你可以通过 Python API 来获取并导出相机的外参矩阵。 blender导出相机参数 1.单张照片2.多张照片&#xff08;视频&#xff09;3.坐标系转换 1.单张照片 import numpy as …

视频监控平台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凸起

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

射频连接器的6个主要指标

射频连接器的6个主要指标 射频连接器是一类用于电子设备和通信系统中的连接器&#xff0c;用于连接射频信号的传输。射频连接器的性能直接影响着设备的信号传输质量和系统的整体性能。在选择和设计射频连接器时&#xff0c;需要考虑几个关键指标。下面将详细介绍射频连接器的6个…

面试:DDD 领域驱动设计

文章目录 请解释下什么是 DDD 领域驱动设计DDD 的四层领域模型是怎样的&#xff1f;包含哪些基础概念&#xff1f;DDD 中的贫血模型和充血模型有什么区别在 DDD 中&#xff0c;如何处理模型的聚合和聚合根DDD 中的实体和值对象有什么区别&#xff1f;在 DDD 中&#xff0c;如何…

python每日一题——12最小覆盖子串

题目 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 “” 。 注意&#xff1a; 对于 t 中重复字符&#xff0c;我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果…

594. 最长和谐子序列 --力扣 --JAVA

题目 和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。 现在&#xff0c;给你一个整数数组 nums &#xff0c;请你在所有可能的子序列中找到最长的和谐子序列的长度。 数组的子序列是一个由数组派生出来的序列&#xff0c;它可以通过删除一些元素或不删除元素…