树的遍历(递归和非递归)
二叉树后序遍历的递归和非递归算法

安 徽电气工 程 职 业 技术学 院学报
:薹6 M2 a r 0 c h 0
.
-X树后序遍历的递归和非递归算法
孙泽宇, 赵国增 , 舒云星・
( 洛阳工业高等专科学校计算机系 , 河南 洛阳 4 10 ) 703
[ 要 ] 论述了二又树后序遍历的递归算法和非递归算法, 摘 对递归算法中的工作栈 的执行过程做 了
Srcbt e t t ie { u r
● 收稿 日期 :0 5—1 0 70 . 2— 2
作者筒介: 孙泽字(97 . 吉林长春人. 17 一) 男。 洛阳工业高等专科学校计算机秉麓师。研究方向: 人工智能。 趟 目增 (97 . 河南越壁人 。 阳工业高等专科 学校计算机 秉麓师 。研究方 向: 1 一) 男。 7 洛 人工智能。
s c br 木e , r h;} t t ie lt 木 i t m te f g
后序遍历二叉树的递归算法如下 :
T p d fs u tBT o e y e e r c in d t
法及执行时栈 的变化情况 , 可设计 出较好 的非递归化算法 , 本文讨论了二叉树后序遍历的递归和非递归
算法。 2 后序遍历二叉树的递归算法
1 后序遍历左子树( ) 若左子树不为空 ) 2 后序遍历右子树( ) 若右子树不为空 ) 3 访问根结点 ( ) 若存在根结点)
二叉树数据结构如下 :
二叉树是数据结构 中最常见 的存储形式 , 在算法与数据结构中经常使用。树与森林都可以转换为 二叉树 , 而遍历算法则是二叉树最重要的操作 。所谓遍历二叉树 , 就是遵从某种次序 , 遍访二叉树 中的
所有结点, 使得每个结点被访问一次 , 而且仅一次。在遍历算法中, 递归算法是最普遍 的, 弄清 了递归算
中序遍历二叉树t的非递归算法 -回复

中序遍历二叉树t的非递归算法-回复中序遍历是二叉树遍历的一种方法,它的特点是先访问左子树,然后访问根节点,最后访问右子树。
在非递归算法中,我们需要借助栈来实现中序遍历。
下面我们将逐步分析如何用非递归算法中序遍历二叉树。
首先,我们需要了解栈的基本知识。
栈是一种后进先出(LIFO)的数据结构,它有两个基本操作:入栈(push)和出栈(pop)。
在中序遍历中,我们将节点按照遍历顺序依次入栈,然后出栈并访问节点。
接下来,我们来介绍中序遍历二叉树的非递归算法。
我们可以通过模拟递归来实现中序遍历。
首先,我们定义一个栈用于存储待访问的节点。
初始时,将根节点入栈。
在每一次迭代中,我们需要判断栈是否为空。
若不为空,则将栈顶节点出栈,并访问该节点。
然后,我们将栈顶节点的右子树入栈。
接下来,将栈顶节点的左子树依次入栈,直到左子树为空。
下面,我们以一个简单的例子来说明这个过程。
假设我们有如下二叉树t:1/ \2 3/ \ / \4 5 6 7我们使用中序遍历的非递归算法来遍历这棵树。
首先,将根节点入栈,此时栈中的元素为[1]。
然后,循环执行以下步骤:1. 判断栈是否为空,栈不为空,执行以下步骤;2. 将栈顶节点出栈,访问该节点;3. 将栈顶节点的右子树入栈;4. 将栈顶节点的左子树依次入栈,直到左子树为空。
按照这个步骤,我们首先将1出栈并访问,然后将右子树入栈,栈中的元素为[2, 3]。
然后,我们继续将左子树入栈,栈中的元素变为[4, 2, 3]。
此时,我们将4出栈并访问,然后将栈中的元素变为[2, 3]。
接着,我们将2出栈并访问,将右子树入栈,栈中的元素变为[5, 3]。
继续将左子树入栈,栈中的元素为[5, 6, 3]。
接着,我们将5出栈并访问,将栈中的元素变为[6, 3]。
最后,我们将6出栈并访问,将右子树入栈,栈中的元素变为[7, 3]。
最后,我们将7出栈并访问,此时栈为空,遍历结束。
通过这个例子,我们可以看到中序遍历的非递归算法确实按照中序遍历的顺序访问了二叉树的所有节点。
考研《数据结构》复习知识点归纳

《数据结构》复习重点知识点归纳一.数据结构的章节结构及重点构成数据结构学科的章节划分基本上为:概论,线性表,栈和队列,串,多维数组和广义表,树和二叉树,图,查找,内排,外排,文件,动态存储分配。
对于绝大多数的学校而言,“外排,文件,动态存储分配”三章基本上是不考的,在大多数高校的计算机本科教学过程中,这三章也是基本上不作讲授的。
所以,大家在这三章上可以不必花费过多的精力,只要知道基本的概念即可。
但是,对于报考名校特别是该校又有在试卷中对这三章进行过考核的历史,那么这部分朋友就要留意这三章了。
按照以上我们给出的章节以及对后三章的介绍,数据结构的章节比重大致为:·概论:内容很少,概念简单,分数大多只有几分,有的学校甚至不考。
·线性表:基础章节,必考内容之一。
考题多数为基本概念题,名校考题中,鲜有大型算法设计题,如果有,也是与其它章节内容相结合。
·栈和队列:基础章节,容易出基本概念题,必考内容之一。
而栈常与其它章节配合考查,也常与递归等概念相联系进行考查。
·串:基础章节,概念较为简单。
专门针对于此章的大型算法设计题很少,较常见的是根据KMP进行算法分析。
·多维数组及广义表:基础章节,基于数组的算法题也是常见的,分数比例波动较大,是出题的“可选单元”或“侯补单元”。
一般如果要出题,多数不会作为大题出。
数组常与“查找,排序”等章节结合来作为大题考查。
·树和二叉树:重点难点章节,各校必考章节。
各校在此章出题的不同之处在于,是否在本章中出一到两道大的算法设计题。
通过对多所学校的试卷分析,绝大多数学校在本章都曾有过出大型算法设计题的历史。
·图:重点难点章节,名校尤爱考。
如果作为重点来考,则多出现于分析与设计题型当中,可与树一章共同构成算法设计大题的题型设计。
·查找:重点难点章节,概念较多,联系较为紧密,容易混淆。
出题时可以作为分析型题目给出,在基本概念型题目中也较为常见。
中序遍历非递归算法

中序遍历非递归算法一、前言在二叉树的遍历中,中序遍历是一种重要的遍历方式。
中序遍历非递归算法是指不使用递归函数,通过循环和栈等数据结构实现对二叉树进行中序遍历。
本文将详细介绍中序遍历非递归算法的实现过程和相关知识点。
二、中序遍历的定义在二叉树中,对每个节点的访问顺序有三种方式:先访问左子树,再访问根节点,最后访问右子树;先访问根节点,再访问左子树和右子树;先访问左子树和右子树,最后访问根节点。
这三种方式分别称为前序遍历、中序遍历和后序遍历。
其中,中序遍历是指按照“先访问左子树,再访问根节点,最后访问右子树”的顺序进行访问。
三、中序遍历非递归算法的思路1. 定义一个空的辅助栈;2. 从二叉树的跟节点开始循环:a. 将当前节点压入辅助栈;b. 如果当前节点存在左孩子,则将当前节点设置为其左孩子,继续循环;c. 如果当前节点不存在左孩子,则从辅助栈中弹出一个节点,并将该节点的值输出;d. 如果被弹出的节点存在右孩子,则将当前节点设置为其右孩子,继续循环;e. 如果被弹出的节点不存在右孩子,则回到步骤c。
四、中序遍历非递归算法的实现1. 定义一个空的辅助栈和一个指向二叉树跟节点的指针cur;2. 对于每个节点,如果该节点不为空或者辅助栈不为空,则进行循环:a. 如果当前节点不为空,则将其压入辅助栈中,并将当前节点更新为其左孩子;b. 如果当前节点为空,则从辅助栈中弹出一个元素,并输出该元素的值;i. 将当前节点更新为被弹出元素的右孩子。
3. 循环结束后,即可完成对二叉树的中序遍历。
五、代码实现以下是Java语言实现中序遍历非递归算法的代码:```public static void inOrder(TreeNode root) {Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;while (cur != null || !stack.isEmpty()) {if (cur != null) {stack.push(cur);cur = cur.left;} else {cur = stack.pop();System.out.print(cur.val + " ");cur = cur.right;}}}```六、时间和空间复杂度中序遍历非递归算法的时间复杂度为O(n),其中n为二叉树节点的个数。
数据结构课程设计报告-最短路径算法-二叉树的三种遍历

数据结构课程设计报告班级:计算机科学与技术132班姓名:赖恒财指导教师:董跃华成绩:32信息工程学院2015 年7月8日目录图的最短路径算法实现1. 需求分析 (1)1.1 程序设计内容 (1)1.2 设计要求 (1)2.概要设计 (2)3.详细设计 (2)3.1 数据类型的定义 (2)3.2 功能模块的设计 (2)3.3 主程序流程 (9)4.调试分析 (10)4.1 问题回顾和分析 (10)4.2.经验和体会 (11)5.测试结果 (12)二叉树的遍历1.设计目的 (13)2.需求分析 (14)2.1课程设计的内容和要求 (14)2.2选题的意义及背景 (14)3.概要设计 (14)3.1设计思想 (14)3.2程序数据类型 (16)3.3程序模块分析 (16)3.3.1置空栈 (16)3.3.2入栈 (17)3.3.3出栈 (17)3.3.4取栈顶操作 (17)3.3.5判空栈 (17)3.4函数关系: (18)4.详细设计 (18)4.1二叉树算法程序截图和结果 (18)5.程序测试结果及问题分析 (19)6.总结 (20)参考文献 (21)附录1 (22)附录2 (26)图的最短路径算法实现----基于floyd最短路径算法1.需求分析设计校园平面图,所含景点不少于8个。
以图中顶点表示学校内各景点,存放景点的名称、景点介绍信息等;以边表示路径,存放路径长度信息。
要求将这些信息保存在文件graph.txt中,系统执行时所处理的数据要对此文件分别进行读写操作。
1.1程序设计内容1.从文件graph.txt中读取相应数据, 创建一个图,使用邻接矩阵表示图;2.景点信息查询:为来访客人提供校园任意景点相关信息的介绍;3.问路查询:为来访客人提供校园任意两个景点之间的一条最短路径。
1.2 设计要求(1) 程序要具在一定的健壮性,即当输入数据非法时,程序也能适当地做出反应。
(2) 程序要添加适当的注释,程序的书写要采用缩进格式。
二叉树的遍历及相关题目

⼆叉树的遍历及相关题⽬⼆叉树的遍历及相关题⽬1.1⼆叉树遍历的概念⼆叉树结构体的定义:typedef struct node{ ElemType data; struct node * lchild; struct node * rchild;}⼆叉树的遍历是指按照⼀定的次序访问⼆叉树中的所有的节点,并且每个节点仅访问⼀次的过程。
若规定先遍历左⼦树,后遍历右⼦树,则对于⾮空⼆叉树,可得到如下3种递归的遍历⽅法:(1)先序遍历访问根节点,先序遍历左⼦树,先序遍历右⼦树。
(根,左,右)(2)中序遍历中序遍历左⼦树,访问根节点,中序遍历右⼦树。
(左,根,右)(3)后序遍历后序遍历左⼦树,后序遍历右⼦树,访问根节点。
(左,右,根)除此之外也有层次遍历。
先访问根节点,在从左到右访问第⼆层的所有节点,从左到右访问第三层的所有节点......1.2⼆叉树遍历递归算法先序遍历递归算法:void PreOrder(BTNode * b){ if(n != NULL) { cout<<b->data; PreOrder(b->lchild); PreOrder(b->rchild); }}中序遍历递归算法void InOrder(BTNode * b){ if(n != NULL) { InOrder(b->lchild); cout<<b->data; InOrder(b->rchild); }}后序遍历递归算法:void PostOrder(BTNode * b){ if(b != NULL) { PostOrder(b->lchild); PostOrder(b->rchild); cout<<b->data; }}题⽬1:输出⼀个给定⼆叉树的所有的叶⼦节点:void DispLeaf(BTNode * b){ if(b != NULL) { if(b->lchild == NULL && b->rchild == NULL) cout<<b->data; DispLeaf(b->lchild); DispLeaf(b->rchild); }}以上算法采⽤先序遍历输出了所有的叶⼦节点,所以叶⼦节点是从左到右输出的。
树的三种遍历方式

树的三种遍历方式树是一种非常重要的数据结构,它在计算机科学中应用广泛。
树可以用于搜索、排序、数据表、文件系统等诸多领域。
而树的遍历方式,则是在树中搜索数据的一种方法。
树的遍历方式有三种,分别是前序遍历、中序遍历和后序遍历。
这三种遍历方式在树的数据结构中有着重要的作用,它们可以用来检索所有节点的信息。
下面我们将对它们一一进行介绍。
1.前序遍历前序遍历也称为先序遍历,它的顺序是根节点->左子树->右子树。
它的算法描述如下:前序遍历的递归算法实现:void PreOrderTraversal(TraversalNode T){ if (T) { visit(T); PreOrderTraversal(T->left); PreOrderTraversal(T->right); } }前序遍历的非递归算法实现:void PreOrderTraversal(TraversalNode T){ while (T || !StackIsEmpty(S)) { while (T) { visit(T); push(Stack,T); T = T->left; } if(!StackIsEmpty(S)) { T = pop(Stack);T = T->right; } } }2.中序遍历中序遍历的顺序是左子树->根节点->右子树。
它的算法描述如下:中序遍历的递归算法实现:void InOrderTraversal(TraversalNode T) { if(T) { InOrderTraversal(T->left);visit(T);InOrderTraversal(T->right); } }中序遍历的非递归算法实现:void InOrderTraversal(TraversalNode T){ while (T || !StackIsEmpty(S)) { while(T) { push(Stack, T); T =T->left; } if (!StackIsEmpty(S)){ T = pop(Stack); visit(T); T = T->right; } } }3.后序遍历后序遍历的顺序是左子树->右子树->根节点。
二叉树的遍历教案教学设计

二叉树的遍历教案教学设计教案教学设计:二叉树的遍历一、教学目标:1. 了解二叉树的遍历方式:前序遍历、中序遍历和后序遍历。
2. 能够使用递归和非递归两种方法实现二叉树的遍历。
3. 能够分析和比较不同遍历方式的时间复杂度和空间复杂度。
二、教学内容:1. 二叉树的遍历概念及分类。
2. 递归遍历算法的原理及实现。
3. 非递归遍历算法的原理及实现。
4. 比较不同遍历方式的时间复杂度和空间复杂度。
三、教学重点:1. 能够理解二叉树的遍历分类及其特点。
2. 能够使用递归和非递归两种方法实现二叉树的遍历。
四、教学难点:1. 非递归遍历算法的实现。
2. 比较不同遍历方式的时间复杂度和空间复杂度。
五、教学过程:1. 导入新知识,激发学生兴趣(5分钟)教师通过展示一棵二叉树的图片引入二叉树的遍历概念,并让学生猜测遍历的意义。
2. 介绍二叉树的遍历分类及特点(10分钟)教师介绍二叉树的遍历分类:前序遍历(根-左-右)、中序遍历(左-根-右)和后序遍历(左-右-根),并讲解每种遍历方式的特点。
3. 介绍递归遍历算法的原理及实现(15分钟)教师通过演示前序遍历的递归算法实现,介绍递归遍历的原理和递归函数的编写,让学生理解递归遍历的思路。
4. 演示递归遍历算法的应用(15分钟)教师在白板上画一棵二叉树,演示如何使用递归算法实现不同的遍历方式,并让学生跟随演示进行练习。
5. 介绍非递归遍历算法的原理及实现(15分钟)教师介绍非递归遍历算法的思路,包括使用栈数据结构进行遍历的原理及实现。
6. 演示非递归遍历算法的应用(15分钟)教师在白板上画一棵二叉树,演示如何使用非递归算法实现不同的遍历方式,并让学生跟随演示进行练习。
7. 比较不同遍历方式的时间复杂度和空间复杂度(10分钟)教师比较不同遍历方式的时间复杂度和空间复杂度,让学生了解不同的遍历方式在不同场景下的优劣。
8. 小结与作业布置(5分钟)教师对本节课进行小结,并布置作业:编写一个程序,实现二叉树的遍历,并分析所用遍历方式的时间复杂度和空间复杂度。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
二叉树的遍历一、设计思想二叉树的遍历分为三种方式,分别是先序遍历,中序遍历和后序遍历。
先序遍历实现的顺序是:根左右,中序遍历实现的是:左根右,后续遍历实现的是:左右根。
根据不同的算法分,又分为递归遍历和非递归遍历。
递归算法:1.先序遍历:先序遍历就是首先判断根结点是否为空,为空则停止遍历,不为空则将左子作为新的根结点重新进行上述判断,左子遍历结束后,再将右子作为根结点判断,直至结束。
到达每一个结点时,打印该结点数据,即得先序遍历结果。
2.中序遍历:中序遍历是首先判断该结点是否为空,为空则结束,不为空则将左子作为根结点再进行判断,打印左子,然后打印二叉树的根结点,最后再将右子作为参数进行判断,打印右子,直至结束。
3.后续遍历:指针到达一个结点时,判断该结点是否为空,为空则停止遍历,不为空则将左子作为新的结点参数进行判断,打印左子。
左子判断完成后,将右子作为结点参数传入判断,打印右子。
左右子判断完成后打印根结点。
非递归算法:1.先序遍历:首先建立一个栈,当指针到达根结点时,打印根结点,判断根结点是否有左子和右子。
有左子和右子的话就打印左子同时将右子入栈,将左子作为新的根结点进行判断,方法同上。
若当前结点没有左子,则直接将右子打印,同时将右子作为新的根结点判断。
若当前结点没有右子,则打印左子,同时将左子作为新的根结点判断。
若当前结点既没有左子也没有右子,则当前结点为叶子结点,此时将从栈中出栈一个元素,作为当前的根结点,打印结点元素,同时将当前结点同样按上述方法判断,依次进行。
直至当前结点的左右子都为空,且栈为空时,遍历结束。
2.中序遍历:首先建立一个栈,定义一个常量flag(flag为0或者1),用flag记录结点的左子是否去过,没有去过为0,去过为1,默认为0.首先将指针指向根结点,将根结点入栈,然后将指针指向左子,左子作为新的结点,将新结点入栈,然后再将指针指向当前结点的左子,直至左子为空,则指针返回,flag置1,出栈一个元素,作为当前结点,打印该结点,然后判断flag,flag为1则将指针指向当前结点右子,将右子作为新的结点,结点入栈,再次进行上面的判断,直至当前结点右子也为空,则再出栈一个元素作为当前结点,一直到结束,使得当前结点右子为空,且栈空,遍历结束。
3.后续遍历:首先建立两个栈,然后定义两个常量。
第一个为status,取值为0,1,2.0代表左右子都没有去过,1代表去过左子,2,代表左右子都去过,默认为0。
第二个常量为flag,取值为0或者1,0代表进左栈,1代表进右栈。
初始时指针指向根结点,判断根结点是否有左子,有左子则,将根结点入左栈,status置0,flag置0,若没有左子则判断结点有没有右子,有右子就把结点入右栈,status置0,flag置1,若左右子都没有,则打印该结点,并将指针指向空,此时判断flag,若flag为0,则从左栈出栈一个元素作为当前结点,重新判断;若flag为1则从右栈出栈一个元素作为当前结点,重新判断左右子是否去过,若status为1,则判断该结点有没有右子,若有右子,则将该结点入右栈,status置1,flag置1,若没有右子,则打印当前结点,并将指针置空,然后再次判断flag。
若当前结点status为2,且栈为空,则遍历结束。
若指针指向了左子,则将左子作为当前结点,判断其左右子情况,按上述方法处理,直至遍历结束。
二、算法流程图图1 二叉树的建立用先序方法建立二叉树,为每个结点定义左右子,用0代表空,得到上述二叉树图2 非递归二叉树遍历先序首先建立一个栈,当指针到达根结点时,打印根结点,判断根结点是否有左子和右子。
有左子和右子的话就打印左子同时将右子入栈,将左子作为新的根结点进行判断,方法同上。
若当前结点没有左子,则直接将右子打印,同时将右子作为新的根结点判断。
若当前结点没有右子,则打印左子,同时将左子作为新的根结点判断。
若当前结点既没有左子也没有右子,则当前结点为叶子结点,此时将从栈中出栈一个元素,作为当前的根结点,打印结点元素,同时将当前结点同样按上述方法判断,依次进行。
直至当前结点的左右子都为空,且栈为空时,遍历结束。
图3 非递归二叉树遍历中序中序遍历:首先建立一个栈,定义一个常量flag(flag为0或者1),用flag记录结点的左子是否去过,没有去过为0,去过为1,默认为0.首先将指针指向根结点,将根结点入栈,然后将指针指向左子,左子作为新的结点,将新结点入栈,然后再将指针指向当前结点的左子,直至左子为空,则指针返回,flag置1,出栈一个元素,作为当前结点,打印该结点,然后判断flag,flag为1则将指针指向当前结点右子,将右子作为新的结点,结点入栈,再次进行上面的判断,直至当前结点右子也为空,则再出栈一个元素作为当前结点,一直到结束,使得当前结点右子为空,且栈空,遍历结束。
图4 非递归二叉树遍历后序首先建立两个栈,然后定义两个常量。
第一个为status,取值为0,1,2.0代表左右子都没有去过,1代表去过左子,2,代表左右子都去过,默认为0。
第二个常量为flag,取值为0或者1,0代表进左栈,1代表进右栈。
初始时指针指向根结点,判断根结点是否有左子,有左子则,将根结点入左栈,status置0,flag置0,若没有左子则判断结点有没有右子,有右子就把结点入右栈,status置0,flag置1,若左右子都没有,则打印该结点,并将指针指向空,此时判断flag,若flag为0,则从左栈出栈一个元素作为当前结点,重新判断;若flag为1则从右栈出栈一个元素作为当前结点,重新判断左右子是否去过,若status 为1,则判断该结点有没有右子,若有右子,则将该结点入右栈,status置1,flag置1,若没有右子,则打印当前结点,并将指针置空,然后再次判断flag。
若当前结点status为2,且栈为空,则遍历结束。
若指针指向了左子,则将左子作为当前结点,判断其左右子情况,按上述方法处理,直至遍历结束。
三、源代码#include<stdio.h>#include<stdlib.h>//用递归的方式遍历二叉树typedef struct node //定义二叉树的结点{ int data; //结点的数据struct node*lChild,*rChild; //结点左右子}Node;int i=-1; //控制下面函数中循环的Node *buildTree(int *b) //产生二叉树(利用先序递归产生){Node *p; //创建一个根结点指针if(b[++i]==0)p=NULL; //如果传入的当前值为0 则设其为空结点else{ p=(Node*)malloc(sizeof(Node)); //开辟内存p->data=b[i]; //设置当前结点的数据p->lChild=buildTree(b); //左子结点p->rChild=buildTree(b); //右子}return p; //把创建的树的根节点返回}void preOrder(Node *root) //前序遍历{下面给出的是用递归算法实现的程序的源代码:if(root!=0) //如果根节点不为0{printf("%d ",root->data); //打印当前结点preOrder(root->lChild); //指向左子preOrder(root->rChild); //指向右子}}void inOrder(Node *root) //中序遍历{if(root!=0) //如果根节点不为0{inOrder(root->lChild); //指向左子printf("%d ",root->data); //打印当前结点inOrder(root->rChild); //指向右子}}void postOrder(Node *root){if(root!=0){postOrder(root->lChild); //指向左子postOrder(root->rChild); //指向右子printf("%d ",root->data); //打印当前结点}}void main(){//按先序次序输入树的结点(非0整数)来创建一个树空结点用0表示int a[] = {1,2,4,0,7,0,0,0,3,5,0,0,6,8,0,0,9,0,0};int *b = a;//将指向数组首地址的指针传给bulidTree 函数来创建树Node *root = buildTree(b);printf("用递归方法\n\n前序遍历: "); //打印提示内容preOrder(root); //调用前序遍历函数printf("\n中序遍历: "); //打印提示内容inOrder(root); //调用中序遍历函数printf("\n后序遍历: "); //打印提示内容postOrder(root); //调用后序遍历函数getch();}下面给出的是用非递归算法实现的程序的源代码:#include<stdio.h>#include<stdlib.h>//用非递归的方式遍历二叉树typedef struct node {int data;struct node *lChild,*rChild;}Node;typedef struct {Node *bottom;Node *top;}Stack;void init(Stack *s) {s->bottom=(Node *)malloc(100*sizeof(Node)); s->top=s->bottom; }int isEmpty(Stack s) {if(s.top==s.bottom)return 1;elsereturn 0;}void push(Stack *s,Node node) {*(s->top++)=node;}Node pop(Stack *s) {Node node;node=*(--(s->top));return node;}Node peek(Stack *s) { return *(s->top-1);}typedef struct {Node *bottom;Node *top;}MyStack;//定义二叉树的结点//结点的数据//结点左右子//创建栈//栈底指针//栈顶指针//初始化栈//为指针开辟内存//栈顶指针指向栈底指针//判断栈是否为空的函数//栈空返回1//不为空返回0//栈的push方法//给栈顶赋值然后top+1//出栈函数//声明一Node类型遍量//node 为栈顶元素然后top-1//返回pop出的结点//看栈顶元素//返回栈顶元素//创建栈(MyStack)结构体//栈底指针//栈顶指针void init1(MyStack *s) //初始化栈{s->bottom=(Node *)malloc(100*sizeof(Node)); //开辟内存s->top=s->bottom; //栈顶指针指向栈底指针}void push1(MyStack *s,Node node) //进栈方法{*(s->top++)=node; //给栈顶赋值然后top+1 }Node pop1(MyStack *s) //出栈函数{Node node; //声明一Node类型遍量node=*(--(s->top)); //node 为栈顶元素然后top-1 return node; //返回pop出的结点} Node peek1(MyStack *s) //查栈顶元素{return *(s->top-1); //返回栈顶元素}int isEmpty1(MyStack s) //判断栈是否为空{if(s.top==s.bottom)return 1; //栈空了返回1 elsereturn 0; //不为空返回0 }int temp=-1;Node *buildTree(int *b) //产生二叉树{Node *p; //创建一个根结点指针if(b[++temp]==0)p=NULL; //如果传入的当前值为0 则设其为空结点else{ p=(Node*)malloc(sizeof(Node)); //开辟内存p->data=b[temp]; //设置当前结点的数据p->lChild=buildTree(b); //左子结点p->rChild=buildTree(b); //右子};return p; //把创建的树的根结点返回}void preOrder(Node *root) //前序遍历{Stack po; //声明一个栈Node curr = *root; //当前结点为根结点init(&po); //初始化找while(curr.data!=0||!isEmpty(po)) //当前结点不为空且栈不为空{if(curr.data==0) //如果当前结点为空{curr=pop(&po); //当前结点指向pop出栈的结点}if(curr.rChild!=NULL) //如果右子为空{push(&po,*curr.rChild); //将右子进栈}printf("%d ",curr.data); //打印当前结点的内容if(curr.lChild!=NULL) //如果左子不为空{ curr=*curr.lChild; //当前子指向左子}else{curr=pop(&po); //当前子指向pop出栈结点}if((curr.lChild==NULL)&&(curr.rChild==NULL)) //如果左子右子都为空{printf("%d ",curr.data); //打印当前结点的内容curr.data=0; //当前结点置空}}}void inOrder(Node *root) //中序遍历{Stack ms; //声明一个栈Node curr = *root; //当前结点指向根结点int flag = 0;//设置一个标志0:当前结点指向了右结点1:当前结点指向了左结点init(&ms); //初始化栈while(curr.data!=0||isEmpty(ms)) //当前结点不为空且栈不为空{if(curr.lChild!=NULL&&flag==0) //左子不为空且没去过左子{push(&ms,curr); //当前子进栈curr=*curr.lChild; //当前结点指向左子}else{printf("%d ",curr.data); //打印当前结点的内容if(curr.rChild!=NULL) //左子为空{curr=*curr.rChild; //指向左子}flag=0; //flag 置0}if(curr.rChild==NULL&&curr.lChild==NULL) //如果左右子都为空{printf("%d ",curr.data); //打印当前结点的内容if(isEmpty(ms)==1)break; //栈空则结束循环curr = pop(&ms); //当前子指向pop出栈的结点flag=1; //flag 置1}}}void postOrder(Node *root) //后序遍历{//声明左右栈如果当前结点有左子则进左栈若没左子但是有右子则进右栈Stack msl; //声明左栈MyStack msr; //声明右栈Node curr = *root; //结点指向树的根结点int flag=0; //设置一个标志0:进左栈1:进右栈//设置一个标志0:没去过左右子树1:去过左子树2:去过右子树(两子树都去过)int status=0;init(&msl); //初始化左栈init(&msr); //初始化右栈while(curr.data!=0||isEmpty(msl)!=0||isEmpty1(msr)!=0) //当前结点不为空且左右栈都不为空{if(status==0&&curr.lChild!=NULL) //没去过左右子树且右子不为空{push(&msl,curr); //当前子进左栈curr = *curr.lChild; //当前子指向左子flag=0; //flag置0}else if(status!=2&&curr.rChild!=NULL) //没去过右子树且右子不为空{push1(&msr,curr); //当前子进右栈curr=*curr.rChild //当前子指向右子flag=1; //flag置1status=0; //status 置0else{printf("%d ",curr.data); //打印当前结点内容//指向右栈弹出的元素//status标志置为2 //如果右栈为空//指向右栈弹出的元素//指向左栈弹出的元素//status标志置为1 //若当前结点为空,结束循环}}Void main(){int Tree[] = {1,2,4,0,7,0,0,0,3,5,0,0,6,8,0,0,9,0,0};int *tree = Tree;Node *root = buildTree(tree); //创建一个结点指向创建的树的根结点printf("用非递归方法\n前序遍历: "); //打印提示内容preOrder(root); //调用前序遍历函数printf("\n中序遍历: "); //打印提示内容inOrder(root); //调用中序遍历函数printf("\n后序遍历"); //打印提示内容postOrder(root); //调用后序遍历函数getch();}curr.data=0;if(curr.data==0)if(flag==0){if(isEmpty(msl)==0){curr = pop(&msl);status=1;}else if(isEmpty1(msr)==0) {curr = pop1(&msr);status=2;}}else { if(isEmpty1(msr)==0) {curr=pop1(&msr);status=2;}else if(isEmpty(msl)==0) {curr=pop(&msl);status=1;}}if(curr.data==0)break;}//当前结点置空//如果当前子为空//如果flag标志为0 //如果左栈不为空//指向左栈弹出的元素//status标志置为1{四、运行结果图5 递归算法运行结果图图6 非递归算法运行结果图.先序遍历非递归算法void PreOrderUnrec(Bitree*t){Stack s;StackInit(s);Bitree*p=t;while(p!=NULL||!StackEmpty(s)){while(p!=NULL)//遍历左子树{visite(p->data);push(s,p);p=p->lchild;}if(!StackEmpty(s))//通过下一次循环中的内嵌while实现右子树遍历{p=pop(s);p=p->rchild;}//endif}//endwhile}2.中序遍历非递归算法void InOrderUnrec(Bitree*t){Stack s;StackInit(s);Bitree*p=t;while(p!=NULL||!StackEmpty(s)){while(p!=NULL)//遍历左子树{push(s,p);p=p->lchild;}if(!StackEmpty(s)){p=pop(s);visite(p->data);//访问根结点p=p->rchild;//通过下一次循环实现右子树遍历}//endif}//endwhile}3.后序遍历非递归算法typedef enum{L,R}tagtype; typedef struct{Bitree ptr;tagtype tag;}stacknode;typedef struct{stacknode Elem[maxsize];int top;}SqStack;void PostOrderUnrec(Bitree t) {SqStack s;stacknode x;StackInit(s);p=t;do{while(p!=null)//遍历左子树{x.ptr=p;x.tag=L;//标记为左子树push(s,x);p=p->lchild;}while(!StackEmpty(s)&&s.Elem[s.top].tag==R){x=pop(s);p=x.ptr;visite(p->data);//tag为R,表示右子树访问完毕,故访问根结点}if(!StackEmpty(s)){s.Elem[s.top].tag=R;//遍历右子树p=s.Elem[s.top].ptr->rchild;}}while(!StackEmpty(s));}//PostOrderUnrec21 / 21。