树的遍历(递归和非递归)

合集下载

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

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

安 徽电气工 程 职 业 技术学 院学报
:薹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的非递归算法 -回复

中序遍历二叉树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. 二叉树的遍历二叉树的遍历是二叉树操作中最基础的操作。

它分为三种遍历方式:前序遍历、中序遍历和后序遍历。

其中,前序遍历是按照“根左右”顺序遍历,中序遍历是按照“左根右”顺序遍历,后序遍历是按照“左右根”顺序遍历。

遍历的实现方式主要有两种:递归和非递归。

递归实现比较简单,非递归实现可以利用栈来实现。

以下是前序遍历的递归实现:void preorderTraversal(TreeNode* root) {if (root != nullptr) {cout << root->val << ' ';preorderTraversal(root->left);preorderTraversal(root->right);}}以下是前序遍历的非递归实现:void preorderTraversal(TreeNode* root) {if (root == nullptr) return;stack<TreeNode*> st;st.push(root);while (!st.empty()) {TreeNode* node = st.top();st.pop();cout << node->val << ' ';if (node->right != nullptr) st.push(node->right);if (node->left != nullptr) st.push(node->left);}}2. 二叉树的最大深度二叉树的最大深度是指从根节点到叶子节点的最长路径上的节点数。

求二叉树的最大深度可以使用递归或BFS(广度优先搜索)实现。

以下是递归实现:int maxDepth(TreeNode* root) {if (root == nullptr) return 0;int leftDepth = maxDepth(root->left);int rightDepth = maxDepth(root->right);return 1 + max(leftDepth, rightDepth);}以下是BFS实现:int maxDepth(TreeNode* root) {if (root == nullptr) return 0;int depth = 0;queue<TreeNode*> q;q.push(root);while (!q.empty()) {int size = q.size();depth++;for (int i = 0; i < size; i++) {TreeNode* node = q.front();q.pop();if (node->left != nullptr) q.push(node->left);if (node->right != nullptr) q.push(node->right);}}return depth;}3. 判断两个二叉树是否相同判断两个二叉树是否相同可以通过递归实现。

二叉树的创建与遍历的实验总结

二叉树的创建与遍历的实验总结

二叉树的创建与遍历的实验总结引言二叉树是一种重要的数据结构,在计算机科学中有着广泛的应用。

了解二叉树的创建和遍历方法对于数据结构的学习和算法的理解至关重要。

本文将对二叉树的创建和遍历进行实验,并总结相应的经验和思考。

二叉树的定义在开始实验之前,我们首先需要了解二叉树的定义和基本概念。

二叉树是一种每个节点最多拥有两个子节点的树形结构。

每个节点包含一个值和指向其左右子节点的指针。

根据节点的位置,可以将二叉树分为左子树和右子树。

创建二叉树二叉树的创建可以采用多种方法,包括手动创建和通过编程实现。

在实验中,我们主要关注通过编程方式实现二叉树的创建。

1. 递归方法递归是一种常用的创建二叉树的方法。

通过递归,我们可以从根节点开始,逐层创建左子树和右子树。

具体步骤如下:1.创建一个空节点作为根节点。

2.递归地创建左子树。

3.递归地创建右子树。

递归方法的代码实现如下所示:class TreeNode:def __init__(self, value):self.value = valueself.left = Noneself.right = Nonedef create_binary_tree(values):if not values:return None# 使用队列辅助创建二叉树queue = []root = TreeNode(values[0])queue.append(root)for i in range(1, len(values)):node = TreeNode(values[i])# 当前节点的左子节点为空,则将新节点作为左子节点if not queue[0].left:queue[0].left = node# 当前节点的右子节点为空,则将新节点作为右子节点elif not queue[0].right:queue[0].right = node# 当前节点的左右子节点已经齐全,可以从队列中删除该节点queue.pop(0)# 将新节点添加到队列中,下一次循环时可以使用该节点queue.append(node)return root2. 非递归方法除了递归方法,我们还可以使用非递归方法创建二叉树。

c语言中序非递归遍历求树的高度

c语言中序非递归遍历求树的高度

C语言是一种广泛应用于系统程序设计和应用软件开发的高级编程语言。

在C语言中,常常需要对树进行遍历操作,以求取树的高度。

其中,序非递归遍历是一种常用的遍历方式。

本文将针对C语言中对树进行序非递归遍历求树的高度进行详细的讲解。

一、序非递归遍历1.序非递归遍历是一种在树的遍历过程中不使用递归的方式。

通过借助栈这一数据结构来完成遍历操作。

2.在序非递归遍历中,我们首先将树的根节点入栈,然后循环执行以下步骤:a.将栈顶节点弹出,并输出该节点的值;b.将该节点的右子节点入栈(如果存在的话);c.将该节点的左子节点入栈(如果存在的话)。

3.直到栈为空为止,遍历结束。

二、求树的高度1.树的高度是指树中从根节点到叶节点的最长路径的节点数。

求树的高度是树的常见操作之一。

2.在进行序非递归遍历的过程中,我们可以借助一个变量来记录树的高度。

具体做法如下:a.在栈中入栈的使用一个额外的变量记录当前节点的高度;b.每次遇到叶子节点时,将该节点的高度与之前记录的最大高度进行比较,并更新最大高度。

3.遍历结束后,最大高度即为树的高度。

三、C语言实现以下是C语言实现序非递归遍历求树高度的示例代码:```c#include <stdio.h>#include <stdlib.h>// 树的节点结构typedef struct Node {int data;struct Node* left;struct Node* right;} Node;// 栈的结构typedef struct Stack {Node* data[100]; // 假设栈的最大容量为100 int top;} Stack;// 初始化栈void init(Stack* s) {s->top = -1;}// 入栈void push(Stack* s, Node* node) {s->data[++(s->top)] = node;}// 出栈Node* pop(Stack* s) {return s->data[(s->top)--];}// 判断栈是否为空int isEmpty(Stack* s) {return s->top == -1;}// 求树高度int getHeight(Node* root) {Stack s;init(s);int maxHeight = 0;Node* curr = root;Node* prev = NULL;while (curr != NULL || !isEmpty(s)) { if (curr != NULL) {push(s, curr);if (s.top + 1 > maxHeight) { maxHeight = s.top + 1;}curr = curr->left;} else {curr = pop(s);curr = curr->right;}}return maxHeight;}// 主函数int m本人n() {// 构建一棵树(这里用简单的示例,实际情况中树的构建可能更加复杂)Node* root = (Node*)malloc(sizeof(Node));root->data = 1;root->left = (Node*)malloc(sizeof(Node));root->left->data = 2;root->left->left = NULL;root->left->right = NULL;root->right = (Node*)malloc(sizeof(Node));root->right->data = 3;root->right->left = NULL;root->right->right = NULL;printf("树的高度为:d\n", getHeight(root));return 0;}四、总结通过以上的讲解和示例代码,我们详细地介绍了C语言中如何利用序非递归遍历求树的高度。

非递归后序遍历求带权路径长度

非递归后序遍历求带权路径长度

非递归后序遍历求带权路径长度1.引言在计算机科学和算法领域中,树是一种常见的数据结构,而树的遍历是对树中所有节点进行访问的一种重要操作。

后序遍历是一种常见的树遍历方式,它的应用场景非常广泛。

今天我们将着重讨论非递归后序遍历,并探讨如何利用非递归后序遍历来求解树中带权路径长度的问题。

2.非递归后序遍历非递归后序遍历是指在遍历树的过程中,不使用递归的方式来实现后序遍历的操作。

它通常借助栈来实现。

我们可以通过模拟递归的过程,在栈的帮助下,实现非递归后序遍历。

这种方式能够有效地降低递归带来的空间开销,提高算法的效率。

3.树的带权路径长度树的带权路径长度是指树中所有节点的路径长度之和。

路径长度是指从根节点到叶子节点的路径上边的权值之和。

带权路径长度可以用来衡量树的结构以及节点之间的关系,它在树的相关问题中有着重要的作用。

4.求解带权路径长度的算法利用非递归后序遍历,我们可以求解树中的带权路径长度。

具体的算法思路如下:•我们使用非递归后序遍历来遍历树的所有节点。

•在遍历的过程中,我们维护一个变量来记录当前节点到根节点的路径长度之和。

•当遍历到叶子节点时,我们将当前节点的路径长度加到带权路径长度中。

•我们就可以得到树的带权路径长度。

5.个人观点和理解在我看来,非递归后序遍历求解带权路径长度是一种非常巧妙的算法设计。

它充分利用了树的特点和后序遍历的思想,通过栈来模拟递归的过程,实现了高效的算法。

而带权路径长度作为一种重要的树的指标,可以帮助我们更好地理解树的结构和特性。

这种算法不仅能够提高我们对树的认识,还能够在实际问题中得到应用。

6.总结通过本文的讨论,我们深入探讨了非递归后序遍历求解带权路径长度的算法。

我们首先介绍了非递归后序遍历的基本概念,然后讨论了树的带权路径长度以及如何利用非递归后序遍历来求解。

我分享了自己的观点和理解。

我相信通过本文的阅读,你不仅对非递归后序遍历有了更深入的理解,也对树的带权路径长度有了更全面的认识。

ds200916_树习题

ds200916_树习题

2014-3-19
北京化工大学信息学院 数据结构
7
ቤተ መጻሕፍቲ ባይዱ

习题——填空题
(1)设有n(n>1)个节点的树,深度最小的树的深度为 , 共有 个非叶节点, 个叶节点。深度最大的树的深度 为 , 共有 个非叶节点, 个叶节点 (2)设高度为h 的二叉树上只有度为0 和度为2 的节点,问该 二叉树的节点数可能的最大值为: ,最小值为: 。 (3)深度为K 的完全二叉树至少有A 个结点,至多有 B 个节点,具有n个节点的完全二叉树,若按自上而 下,从左到右依次给节点编号,则编号最小的叶节点的 序号是C 。当i 为为奇数且不等于1 时,结点i 的兄 弟节点是D ,否则节点i没有左兄弟;但i 为偶数且 不等于n 时,节点i 的右兄弟是节点E ,否则节点i 没有右兄弟。 (4)一棵完全二叉树有200 个结点,则度为1 的结点有 个。 度为0 的结点有 个。度为2 的结点有 个。 (5)具有10 个结点的Huffman 树,最大高度为 ,最小高 度为 。
2014-3-19
北京化工大学信息学院 数据结构
10

习题——选择题
(1)如果结点A 有3 个兄弟,而且B 是A 的双亲,则B 的度为b。 a) 3 b) 4 c) 5 d) 1 (2)设结点X 有左孩子结点Y,右孩子结点Z,用三种基本遍历方 法得到的遍历序列中X c 是Y 的前驱,X c 是Z 的后继,Y a 是Z 的前驱。 a) 一定;b) 不;c) 不一定。 (3)树是结点的有限集合,它有A(a) 根结点,记为T。其余的结 点分成m(m>=0)个B(a) 的集合。一个结点的子结点的个数称 为该结点的C(c)。二叉树与树是不同的概念,二叉树也是结 点的集合,它有D(a)个根结点。 A,D: a) 有0 个或1 个;b) 有0 个或多个; c) 有且只有一个;d) 有一个或一个以上。 B: a) 互不相交; b) 允许相交; c) 允许叶结点相交;d) 允许树枝结点相交。 C:a) 权; b) 维数;c) 度;d) 序。

三种遍历树的方法

三种遍历树的方法

三种遍历树的⽅法树的概念在开发⾥⾯是很重要的⼀部分,xml的⽂档对象模型(DOM)就是⼀棵树,⽂件夹⽂件的结构也是⼀棵树。

遍历树是开发中经常要遇到的⼀个问题,⽐如,要找出DOM⾥⾯的img 标签的个数,就要遍历⼀棵DOM树。

要在⼀个⽬录⾥⾯查找是否有⼀个⽂件也要⽤到遍历这个⽬录。

在这⾥我们以遍历⽂件为例,说明遍历树的三种基本的⽅法:递归深度优先算法,⾮递归深度优先算法,⾮递归⼴度优先算法。

这些算法是我们在项⽬中经常重复的⼀些算法,我感觉我写程序以来,我做的⼤多数算法都⽤了⼤⼆学的那本数据结构,有些时候,只是改装⼀些⼀些算法,有些时候也只是把⼏种算法合并⼀下,也许这是为什么数据结构这本书这样重要的原因。

先看代码:<?phpdefine('DS', DIRECTORY_SEPARATOR);function rec_list_files($from = '.'){if(!is_dir($from)) {return array();}$files = array();if($dh = opendir($from)){while(false !== ($file = readdir($dh))) {if($file == '.' || $file == '..') {continue;}$path = $from . DS . $file;if (is_file($path)) {$files[] = $path;}$files = array_merge($files, rec_list_files($path));}closedir($dh);}return$files;}function deep_first_list_files($from = '.'){if(!is_dir($from)) {return false;}$files = array();$dirs = array($from);while(NULL !== ($dir = array_pop($dirs))) {if( $dh = opendir($dir)) {while( false !== ($file = readdir($dh))) {if($file == '.' || $file == '..') {continue;}$path = $dir . DS . $file;if(is_dir($path)) {$dirs[] = $path;} else {$files[] = $path;}}closedir($dh);}}return$files;}function breadth_first_files($from = '.') {$queue = array(rtrim($from, DS).DS);// normalize all paths$files = array();while($base = array_shift($queue )) {if (($handle = opendir($base))) {while (($child = readdir($handle)) !== false) {if( $child == '.' || $child == '..') {continue;}if (is_dir($base.$child)) {$combined_path = $base.$child.DS;array_push($queue, $combined_path);} else {$files[] = $base.$child;}}closedir($handle);} // else unable to open directory => NEXT CHILD}return$files; // end of tree, file not found}function profile($func, $trydir){$mem1 = memory_get_usage();echo '<pre>----------------------- Test run for '.$func.'() ';flush();$time_start = microtime(true);$list = $func($trydir);//print_r($list);$time = microtime(true) - $time_start;echo 'Finished : '.count($list).' files</pre>';$mem2 = memory_get_peak_usage();printf('<pre>Max memory for '.$func.'() : %0.2f kbytes Running time for '.$func.'() : %0.f s</pre>',($mem2-$mem1)/1024.0, $time);return$list;}profile('rec_list_files', "D:\www\server");profile('deep_first_list_files', "D:\www\server");profile('breadth_first_files', "D:\www\server");>rec_list_files 是递归的深度优先的算法,这个是⽤⼀个简单的函数递归来实现,⽤array_merge 来合并数组deep_first_list_files 是⾮递归的深度优先的算法,⽤了⼀个栈来实现。

三种遍历方法

三种遍历方法

三种遍历方法一、前序遍历前序遍历是二叉树遍历的一种方法,也是最常见的遍历方式之一。

在前序遍历中,首先访问根节点,然后递归地遍历左子树,最后递归地遍历右子树。

前序遍历的应用非常广泛,例如在二叉树的构建和重建、树的深度优先搜索等问题中都会用到前序遍历。

在进行前序遍历时,可以采用递归或者非递归的方式。

1. 递归实现前序遍历:递归实现前序遍历非常简单,具体步骤如下:- 首先判断当前节点是否为空,若为空则返回;- 访问当前节点;- 递归遍历左子树;- 递归遍历右子树。

2. 非递归实现前序遍历:非递归实现前序遍历需要借助栈来实现,具体步骤如下:- 将根节点入栈;- 循环执行以下步骤,直到栈为空:- 弹出栈顶节点,并访问该节点;- 若该节点的右子节点不为空,则将右子节点入栈;- 若该节点的左子节点不为空,则将左子节点入栈。

二、中序遍历中序遍历是二叉树遍历的另一种方法,同样也是一种常用的遍历方式。

在中序遍历中,首先递归地遍历左子树,然后访问根节点,最后递归地遍历右子树。

中序遍历的应用也非常广泛,例如在二叉搜索树的操作中,中序遍历可以按照升序输出所有节点的值。

1. 递归实现中序遍历:递归实现中序遍历的步骤如下:- 首先判断当前节点是否为空,若为空则返回;- 递归遍历左子树;- 访问当前节点;- 递归遍历右子树。

2. 非递归实现中序遍历:非递归实现中序遍历同样需要借助栈来实现,具体步骤如下:- 将根节点入栈;- 循环执行以下步骤,直到栈为空:- 若当前节点不为空,则将当前节点入栈,并将当前节点指向其左子节点;- 若当前节点为空,则弹出栈顶节点,并访问该节点,然后将当前节点指向其右子节点。

三、后序遍历后序遍历是二叉树遍历的另一种方式,也是最后一种常见的遍历方式。

在后序遍历中,首先递归地遍历左子树,然后递归地遍历右子树,最后访问根节点。

后序遍历的应用也非常广泛,例如在二叉树的删除操作中,需要先删除子节点,再删除根节点。

树的后序遍历非递归算法

树的后序遍历非递归算法

树的后序遍历非递归算法
树的后序遍历是一种常用的算法,它可以让我们遍历树结构的所有
节点,并按照一定的顺序进行处理。

而非递归算法则是解决树的遍历
问题的一种常用方法。

下面就为大家介绍一下树的后序遍历的非递归算法:
1. 首先我们需要创建一个堆栈,用于保存遍历过程中的节点。

同时,
我们需要定义一个指针指向当前操作的节点,初始值为根节点。

2. 然后我们开始遍历树,先将根节点入栈。

接下来进入一个循环:
3. 在循环中,我们将指针向左移动,直到遇到一个没有左子节点的节
点为止。

在这个移动的过程中,我们需要将每个遍历过的节点都入栈。

4. 如果当前节点没有右子节点,或者当前节点的右子节点已经入栈,
那么就可以对当前节点进行操作(例如打印出当前节点的值,或者将
其从堆栈中弹出),并将指针指向堆栈中的下一个节点。

5. 如果当前节点存在右子节点,并且其右子节点还没有入栈,则将其
右子节点入栈。

6. 重复步骤3~5,直到堆栈为空为止。

这就完成了一次树的后序遍历。

通过上述非递归算法,我们可以很容易地遍历整棵树,并进行各种自定义操作。

同时,由于使用了堆栈的存储方式,算法复杂度相比递归算法也有了一定程度的优化。

简要说明树的遍历算法

简要说明树的遍历算法

简要说明树的遍历算法树的遍历算法是指按照一定的规则对树中各个节点进行访问的过程。

常见的树的遍历算法包括先序遍历、中序遍历、后序遍历和层次遍历。

下面将对这四种遍历算法进行详细介绍。

一、先序遍历先序遍历又称前序遍历,是指从根节点开始,按照“根左右”的顺序依次访问每个节点。

具体实现方式可以采用递归或者非递归方式。

1. 递归实现递归实现先序遍历比较简单,只需要按照“根左右”的顺序依次访问每个节点即可。

具体实现代码如下:```pythondef preorder(root):if root:print(root.val)preorder(root.left)preorder(root.right)```2. 非递归实现非递归实现先序遍历需要借助栈来实现。

首先将根节点入栈,然后循环执行以下操作:弹出栈顶元素并访问;如果该节点有右子节点,则将其入栈;如果该节点有左子节点,则将其入栈。

具体实现代码如下:```pythondef preorder(root):if not root:return []stack, res = [root], []while stack:node = stack.pop()res.append(node.val)if node.right:stack.append(node.right)if node.left:stack.append(node.left)return res```二、中序遍历中序遍历是指从根节点开始,按照“左根右”的顺序依次访问每个节点。

具体实现方式同样可以采用递归或者非递归方式。

1. 递归实现递归实现中序遍历也比较简单,只需要按照“左根右”的顺序依次访问每个节点即可。

具体实现代码如下:```pythondef inorder(root):if root:inorder(root.left)print(root.val)inorder(root.right)```2. 非递归实现非递归实现中序遍历同样需要借助栈来实现。

树知识点

树知识点

树1.树的递归定义:一个树(或树形)就是一个有限非空的结点集合T,其中:(1)有一个特别标出的被称为该树(或树形)之根root(T)的结点;(2)其余结点(根除外)被分成m≥0 个不相交的集合T1,T2,…,Tm,且T1,T2,…,Tm又都是树(或树形)。

树(或树形)T1,T2,…,Tm被称作root(T)的子树(或子树形)。

2.树的非递归定义:树是包含n ( n ≥1 )个结点且满足如下条件的有限集合:(1)存在一个唯一的结点v0,它没有前驱结点,称为树的根(或根结点);(2)任何非根结点都有且仅有一个前驱结点,称为该结点的父结点;(3)任何结点都可能有多个(≤n-1)后继结点,称之为该结点的子结点;若某结点没有后继结点,则称之为叶结点。

(4)任一非根结点vk都有且仅有一条从v0到该结点的结点序列(或曰路径)v0→v1→vk,其中vi是vi-1(1≤i≤k)的子结点。

3.一个结点的子结点的数目,称为该结点的度或者次数。

一棵树的度为maxi=1,…, n D (i),其中n为树中结点总数,i指树中的第i个结点,D(i)表结点i的度。

4.度为0的结点被称为叶结点;度>0的结点被称为分支结点5.树形T中结点的层数递归定义如下:⑴root(T)层数为零;⑵其余结点的层数为其前驱结点的层数加16.从根结点到某个结点的路径长度恰为该结点的层数7.一棵树中若存在结点vm到vn的路径,则称vn为vm的子孙结点,vm为vn的祖先结点8.一个结点到它的某个子孙结点有且仅有一条路径9.树的高度是指树中结点的最大层数10.树的表示方法:(1)集合嵌套表示法(2)凹入表示法(3)广义表表示法(4)树形表示法11.二叉树(形)是结点的有限集合,它或者是空集,或者由一个根及两个不相交的称为这个根的左、右子树形的二叉树组成。

12.树与二叉树的主要区别:⑴二叉树中结点的子树分成左子树和右子树,即使某结点只有一棵子树,也要指明该子树是左子树,还是右子树,就是说二叉树是有序的;⑵树决不能为空(换言之树不能为空集),即它至少有一个结点,而一棵二叉树可以是空的(或者说二叉树可以为空集)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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。

相关文档
最新文档