算法与数据结构实验报告——树及其应用

合集下载

数据结构树的实验报告

数据结构树的实验报告

数据结构树的实验报告数据结构树的实验报告一、引言数据结构是计算机科学中的重要概念,它可以帮助我们组织和管理数据,提高程序的效率和性能。

而树作为一种常见的数据结构,具有广泛的应用。

本实验旨在通过实践操作,深入理解树的基本概念、特性和操作。

二、实验目的1. 掌握树的基本概念和特性;2. 熟悉树的基本操作,如插入、删除、查找等;3. 理解树的遍历算法,包括前序、中序和后序遍历;4. 实现树的基本功能,并验证其正确性和效率。

三、实验过程1. 构建树的数据结构首先,我们需要定义树的数据结构。

树由节点组成,每个节点可以有零个或多个子节点。

我们可以使用面向对象的思想,创建一个节点类和树类。

节点类包含节点值和子节点列表的属性,以及插入、删除子节点等操作的方法。

树类则包含根节点的属性和遍历方法等。

2. 插入和删除节点在树中插入和删除节点是常见的操作。

插入节点时,我们需要找到合适的位置,并将新节点作为子节点添加到相应的位置。

删除节点时,我们需要考虑节点的子节点和兄弟节点的关系,并进行相应的调整。

通过实现这两个操作,我们可以更好地理解树的结构和特性。

3. 查找节点树中的节点可以通过值进行查找。

我们可以使用递归或迭代的方式,在树中进行深度优先或广度优先的搜索。

在查找过程中,我们需要注意节点的存在性和唯一性,以及查找算法的效率。

4. 树的遍历树的遍历是指按照一定的顺序访问树中的所有节点。

常见的遍历方式有前序、中序和后序遍历。

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

通过实现这三种遍历算法,我们可以更好地理解树的结构和遍历过程。

五、实验结果与分析通过实验,我们成功地实现了树的基本功能,并验证了其正确性和效率。

我们可以通过插入和删除节点操作,构建出不同形态的树,并进行查找和遍历操作。

在插入和删除节点时,树的结构会发生相应的变化,但其基本特性仍然保持不变。

数据结构实验三实验报告

数据结构实验三实验报告

数据结构实验三实验报告数据结构实验三实验报告一、实验目的本次实验的目的是通过实践掌握树的基本操作和应用。

具体来说,我们需要实现一个树的数据结构,并对其进行插入、删除、查找等操作,同时还需要实现树的遍历算法,包括先序、中序和后序遍历。

二、实验原理树是一种非线性的数据结构,由结点和边组成。

树的每个结点都可以有多个子结点,但是每个结点只有一个父结点,除了根结点外。

树的基本操作包括插入、删除和查找。

在本次实验中,我们采用二叉树作为实现树的数据结构。

二叉树是一种特殊的树,每个结点最多只有两个子结点。

根据二叉树的特点,我们可以使用递归的方式实现树的插入、删除和查找操作。

三、实验过程1. 实现树的数据结构首先,我们需要定义树的结点类,包括结点值、左子结点和右子结点。

然后,我们可以定义树的类,包括根结点和相应的操作方法,如插入、删除和查找。

2. 实现插入操作插入操作是将一个新的结点添加到树中的过程。

我们可以通过递归的方式实现插入操作。

具体来说,如果要插入的值小于当前结点的值,则将其插入到左子树中;如果要插入的值大于当前结点的值,则将其插入到右子树中。

如果当前结点为空,则将新的结点作为当前结点。

3. 实现删除操作删除操作是将指定的结点从树中移除的过程。

我们同样可以通过递归的方式实现删除操作。

具体来说,如果要删除的值小于当前结点的值,则在左子树中继续查找;如果要删除的值大于当前结点的值,则在右子树中继续查找。

如果要删除的值等于当前结点的值,则有三种情况:- 当前结点没有子结点:直接将当前结点置为空。

- 当前结点只有一个子结点:将当前结点的子结点替代当前结点。

- 当前结点有两个子结点:找到当前结点右子树中的最小值,将其替代当前结点,并在右子树中删除该最小值。

4. 实现查找操作查找操作是在树中寻找指定值的过程。

同样可以通过递归的方式实现查找操作。

具体来说,如果要查找的值小于当前结点的值,则在左子树中继续查找;如果要查找的值大于当前结点的值,则在右子树中继续查找。

树及其应用的实验原理

树及其应用的实验原理

树及其应用的实验原理一、树的定义与性质树是一种常用的数据结构,它由节点和连接节点的边组成。

树的定义如下:1.每个树都有一个根节点,根节点没有父节点。

2.每个节点可以有零个或多个子节点。

3.每个非根节点都有且只有一个父节点。

4.在树中,从任意一个节点到达另一个节点的路径是唯一的。

树具有以下性质:1.树的节点可以按层次划分为不同的层级。

2.每个节点的子节点的顺序是确定的。

3.每个节点可以有任意个子节点。

二、树的表示方法树的表示方法有多种,常用的包括以下几种:1.链表实现:每个节点包含一个键和一个指向左子树和右子树的指针。

此方法的优点是方便插入和删除节点,但访问节点的时间复杂度较高。

2.数组实现:树可以被转换为一个大小为n的数组,其中n是树中节点的数量。

根节点的索引为1,左子节点的索引为2i,右子节点的索引为2i+1。

此方法的优点是访问节点的时间复杂度低,但插入和删除节点的操作较复杂。

3.哈希表实现:使用哈希表来表示树的结构,每个节点的键值对应一个哈希表的键值。

此方法的优点是查找、插入和删除操作的时间复杂度都为O(1),但空间复杂度较高。

三、树的遍历树的遍历是指按照一定的顺序访问树中的节点。

常用的树的遍历方法有三种:1.前序遍历:先访问根节点,然后按照从左到右的顺序访问左子树和右子树。

2.中序遍历:先按照从左到右的顺序访问左子树,然后访问根节点,最后访问右子树。

3.后序遍历:先按照从左到右的顺序访问左子树和右子树,然后访问根节点。

树的遍历可以使用递归或者迭代的方式来实现,其中递归是一种简单直观的方法。

四、树的应用树作为一种常见的数据结构,在计算机科学和相关领域中有广泛的应用,以下是树的一些应用场景:1.文件系统:文件系统通常使用树的结构来组织文件和目录。

每个目录是一个树节点,文件是树的叶子节点。

2.数据库索引:数据库使用树的结构来建立索引,以提高查询和插入数据的效率。

常用的索引结构包括B树和B+树。

3.编译器:编译器使用语法树来解析源代码,并生成中间代码或目标代码。

树的实现及其应用

树的实现及其应用

树的实现及其应用树(Tree)是一种非常重要的数据结构,它在计算机科学中有着广泛的应用。

树是由节点(Node)和边(Edge)组成的一种层次结构,其中一个节点可以有零个或多个子节点。

树结构中最顶层的节点称为根节点(Root),最底层的节点称为叶节点(Leaf),除了根节点外,每个节点有且仅有一个父节点。

一、树的基本概念在树的结构中,每个节点可以有多个子节点,这些子节点又可以有自己的子节点,以此类推,形成了树的层次结构。

树的基本概念包括以下几个要点:1. 根节点(Root):树结构的最顶层节点,没有父节点。

2. 叶节点(Leaf):树结构的最底层节点,没有子节点。

3. 父节点(Parent):一个节点的直接上级节点。

4. 子节点(Child):一个节点的直接下级节点。

5. 兄弟节点(Sibling):具有相同父节点的节点互为兄弟节点。

6. 子树(Subtree):树中的任意节点和它的子节点以及这些子节点的子节点构成的子树。

7. 深度(Depth):从根节点到某个节点的唯一路径的边的数量。

8. 高度(Height):从某个节点到叶节点的最长路径的边的数量。

二、树的实现树的实现可以通过多种方式来完成,其中最常见的是使用节点和指针的方式来表示树结构。

在实际编程中,可以通过定义节点类(NodeClass)来表示树的节点,然后通过指针来连接各个节点,从而构建出完整的树结构。

下面是一个简单的树节点类的示例代码:```pythonclass TreeNode:def __init__(self, value):self.value = valueself.children = []```在上面的示例中,TreeNode类表示树的节点,每个节点包含一个值(value)和一个子节点列表(children)。

通过不断地创建节点对象并将它们连接起来,就可以构建出一棵完整的树。

三、树的遍历树的遍历是指按照一定顺序访问树中的所有节点。

树的应用实验原理

树的应用实验原理

树的应用实验原理1. 引言树是一种常见的数据结构,它的应用非常广泛。

在计算机科学领域中,树的应用涉及到很多方面,包括算法、数据库、操作系统等。

本文将介绍一些树的应用实验原理。

2. 树的基本概念在开始讨论树的应用实验原理之前,我们先来回顾一下树的基本概念。

树是由节点(node)和边(edge)组成的一个非线性数据结构。

树的特点是每个节点都有零个或多个子节点,而且除了根节点,每个子节点只有一个父节点。

3. 树的应用实验原理3.1. 文件系统树被广泛应用于文件系统中,用于组织和管理文件和目录。

文件系统可以看作是一棵树,根节点表示文件系统的根目录,每个子目录表示一个节点,子目录下的文件或子目录表示子节点。

以下是文件系统树的示例: - 根目录 - 文件1 - 子目录1 - 文件2 - 子目录2 - 文件33.2. 数据库树也被广泛应用于数据库中,用于组织和存储数据。

数据库中的树通常被称为B树(B-tree),它是一种自平衡的树结构,可以高效地进行插入、删除和查找操作。

B树通常用于存储索引数据,例如在关系型数据库中,每个表可能都有一个或多个索引,用于加速数据的检索。

B树的原理是将数据按照一定的规则组织成一个树状结构,使得每个节点都包含一定范围的数据,并通过比较节点的关键字来进行快速查找。

3.3. 操作系统在操作系统中,树被用于描述进程的关系。

每个进程都有一个父进程和零个或多个子进程,这些进程之间形成了一棵进程树。

操作系统使用树的结构来实现进程的管理和调度。

根节点通常表示操作系统的初始化进程,每个子节点表示一个进程,子节点下的进程表示子进程。

通过树的结构,操作系统可以方便地管理进程之间的关系,包括创建、终止、调度等操作。

4. 总结本文介绍了树的应用实验原理。

树被广泛应用于文件系统、数据库和操作系统中。

文件系统中的树用于组织和管理文件和目录,数据库中的树用于存储索引数据,操作系统中的树用于描述进程的关系。

树的应用大大提高了数据的组织和管理效率,是计算机科学领域中非常重要的数据结构之一。

树的应用算法与数据结构

树的应用算法与数据结构

《算法与数据结构》实验报告(一) 实验题目:树的应用1、实验目的:(1)针对问题的实际要求,正确应用树形结构组织和存储数据;(2)掌握二叉树的存储方法。

(3)掌握二叉树的各种遍历方法。

2、实验内容: 二叉树后序遍历的非递归算法。

3、实验说明:二叉树后序遍历的非递归算法:结点要入两次栈,出两次栈;为了区别同一个结点的两次出栈,设置标志flag ,当结点进、出栈时,其标志flag 也同时进、出栈。

设根指针为root ,则可能有以下两种情况:⑴ 若root!=NULL ,则root 及标志flag (置为1)入栈,遍历其左子树;⑵ 若root=NULL ,此时若栈空,则整个遍历结束;若栈不空,则表明栈顶结点的左子树或右子树已遍历完毕。

若栈顶结点的标志flag=1,则表明栈顶结点的左子树已遍历完毕,将flag 修改为2,并遍历栈顶结点的右子树;若栈顶结点的标志flag=2,则表明栈顶结点的右子树也遍历完毕,输出栈顶结点。

二叉树后序遍历的非递归算法伪代码如下:设计分析在后序遍历中,在输出一个结点之前,要两次经历该结点。

第一次是从该结点出发沿其左孩子指针遍历其左子树,第二次是沿其右孩子指针遍历其右子树。

只有右子树遍历完成之后,才能访问该结点。

因此,一个结点要分两次进栈,只有第二次出栈时,才能访问该结点。

也就是说,在后序遍历中要区分是从左子树返回还是从右子树返回,在结点入栈时,必须同时压入一个标记,用该标记指明返回的情况。

所以基本思路1 第一次出栈,只遍历完左子树,该结点不能访问2 第二次出栈,遍历完右子树,该结点可以访问 flag = 1. 栈s 初始化; 2. 循环直到root 为空且栈s 为空 2.1 当root 非空时循环 2.1.1将root 连同标志flag=1入栈; 2.1.2 继续遍历root 的左子树; 2.2 当栈s 非空且栈顶元素的标志为2时,出栈并输出栈顶结点; 2.3 若栈非空,将栈顶元素的标志改为2,准备遍历栈顶结点的右子树;1.从根开始,不断将左子树指针压栈,直到指针为空为止;2.看栈顶元素如果它没有右孩子,或者它的右孩子刚被访问过,访问该结点,弹栈;转到2;否则它的右孩子不空且未被访问过,则必须将它的右孩子继续压栈;转到1;3.栈空,则结束。

数据结构实验报告

数据结构实验报告

数据结构实验报告树是一种非线性的数据结构,它由节点和边组成,节点之间存在层次关系。

树的应用十分广泛,特别是在存储和检索数据上。

在本次实验中,我对树的应用进行了研究和实践,并撰写了本篇实验报告。

本次实验中,我首先学习了树的基本概念和相关术语。

树由根节点、子节点、叶节点以及它们之间的连接边组成。

每个节点可以有多个子节点,但只能有一个父节点(除了根节点)。

叶节点是没有子节点的节点。

这种层次结构使得树可以用来表示具有层次关系的数据,例如家谱、目录结构等。

接下来,我学习了树的不同种类和它们的特点。

最常见的树结构包括二叉树、二叉树(BST)、平衡二叉树、AVL树等。

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

二叉树是二叉树的一种特殊形式,其中左子树的所有节点值都小于根节点的值,右子树的所有节点值都大于根节点的值。

平衡二叉树是一种高度平衡的二叉树,它的左右子树的高度差不超过1、AVL树是一种自平衡的二叉树,它通过旋转和重新平衡来保持树的平衡性。

为了更好地理解树的应用,我选择了二叉树(BST)作为本次实验的主要研究对象。

BST是一种高效的数据结构,可以用来存储一组有序的数据,并且支持快速的查找、插入和删除操作。

我首先实现了BST的基本操作,包括插入节点、删除节点和查找节点。

通过这些操作,我可以在BST中存储和检索数据。

在插入节点时,我按照BST的特性将节点插入到相应的位置,并保持树的有序性。

在删除节点时,我考虑了不同的情况,包括删除叶节点、删除只有一个子节点的节点以及删除有两个子节点的节点。

在查找节点时,我使用了递归的方式在树中查找节点的值。

接着,我实现了一些BST的扩展操作。

首先是中序遍历,它可以按照节点的值的升序输出BST中的所有节点。

其次是最小值和最大值的查找,它们分别返回BST中的最小值和最大值。

最后是查找一些节点的前驱和后继,前驱是小于该节点的最大节点,后继是大于该节点的最小节点。

这些扩展操作可以进一步提升BST的功能和灵活性。

数据结构实验报告-树(二叉树)

数据结构实验报告-树(二叉树)

实验5:树(二叉树)(采用二叉链表存储)一、实验项目名称二叉树及其应用二、实验目的熟悉二叉树的存储结构的特性以及二叉树的基本操作。

三、实验基本原理之前我们都是学习的线性结构,这次我们就开始学习非线性结构——树。

线性结构中结点间具有唯一前驱、唯一后继关系,而非线性结构中结点的前驱、后继的关系并不具有唯一性。

在树结构中,节点间关系是前驱唯一而后继不唯一,即结点之间是一对多的关系。

直观地看,树结构是具有分支关系的结构(其分叉、分层的特征类似于自然界中的树)。

四、主要仪器设备及耗材Window 11、Dev-C++5.11五、实验步骤1.导入库和预定义2.创建二叉树3.前序遍历4.中序遍历5.后序遍历6.总结点数7.叶子节点数8.树的深度9.树根到叶子的最长路径10.交换所有节点的左右子女11.顺序存储12.显示顺序存储13.测试函数和主函数对二叉树的每一个操作写测试函数,然后在主函数用while+switch-case的方式实现一个带菜单的简易测试程序,代码见“实验完整代码”。

实验完整代码:#include <bits/stdc++.h>using namespace std;#define MAX_TREE_SIZE 100typedef char ElemType;ElemType SqBiTree[MAX_TREE_SIZE];struct BiTNode{ElemType data;BiTNode *l,*r;}*T;void createBiTree(BiTNode *&T){ElemType e;e = getchar();if(e == '\n')return;else if(e == ' ')T = NULL;else{if(!(T = (BiTNode *)malloc(sizeof (BiTNode)))){cout << "内存分配错误!" << endl;exit(0);}T->data = e;createBiTree(T->l);createBiTree(T->r);}}void createBiTree2(BiTNode *T,int u) {if(T){SqBiTree[u] = T->data;createBiTree2(T->l,2 * u + 1);createBiTree2(T->r,2 * u + 2); }}void outputBiTree2(int n){int cnt = 0;for(int i = 0;cnt <= n;i++){cout << SqBiTree[i];if(SqBiTree[i] != ' ')cnt ++;}cout << endl;}void preOrderTraverse(BiTNode *T) {if(T){cout << T->data;preOrderTraverse(T->l);preOrderTraverse(T->r);}}void inOrderTraverse(BiTNode *T) {if(T){inOrderTraverse(T->l);cout << T->data;inOrderTraverse(T->r);}}void beOrderTraverse(BiTNode *T){if(T){beOrderTraverse(T->l);beOrderTraverse(T->r);cout << T->data;}}int sumOfVer(BiTNode *T){if(!T)return 0;return sumOfVer(T->l) + sumOfVer(T->r) + 1;}int sumOfLeaf(BiTNode *T){if(!T)return 0;if(T->l == NULL && T->r == NULL)return 1;return sumOfLeaf(T->l) + sumOfLeaf(T->r);}int depth(BiTNode *T){if(!T)return 0;return max(depth(T->l),depth(T->r)) + 1;}bool LongestPath(int dist,int dist2,vector<ElemType> &ne,BiTNode *T) {if(!T)return false;if(dist2 == dist)return true;if(LongestPath(dist,dist2 + 1,ne,T->l)){ne.push_back(T->l->data);return true;}else if(LongestPath(dist,dist2 + 1,ne,T->r)){ne.push_back(T->r->data);return true;}return false;}void swapVer(BiTNode *&T){if(T){swapVer(T->l);swapVer(T->r);BiTNode *tmp = T->l;T->l = T->r;T->r = tmp;}}//以下是测试程序void test1(){getchar();cout << "请以先序次序输入二叉树结点的值,空结点用空格表示:" << endl; createBiTree(T);cout << "二叉树创建成功!" << endl;}void test2(){cout << "二叉树的前序遍历为:" << endl;preOrderTraverse(T);cout << endl;}void test3(){cout << "二叉树的中序遍历为:" << endl;inOrderTraverse(T);cout << endl;}void test4(){cout << "二叉树的后序遍历为:" << endl;beOrderTraverse(T);cout << endl;}void test5(){cout << "二叉树的总结点数为:" << sumOfVer(T) << endl;}void test6(){cout << "二叉树的叶子结点数为:" << sumOfLeaf(T) << endl; }void test7(){cout << "二叉树的深度为:" << depth(T) << endl;}void test8(){int dist = depth(T);vector<ElemType> ne;cout << "树根到叶子的最长路径:" << endl;LongestPath(dist,1,ne,T);ne.push_back(T->data);reverse(ne.begin(),ne.end());cout << ne[0];for(int i = 1;i < ne.size();i++)cout << "->" << ne[i];cout << endl;}void test9(){swapVer(T);cout << "操作成功!" << endl;}void test10(){memset(SqBiTree,' ',sizeof SqBiTree);createBiTree2(T,0);cout << "操作成功!" << endl;}void test11(){int n = sumOfVer(T);outputBiTree2(n);}int main(){int op = 0;while(op != 12){cout << "-----------------menu--------------------" << endl;cout << "--------------1:创建二叉树--------------" << endl;cout << "--------------2:前序遍历----------------" << endl;cout << "--------------3:中序遍历----------------" << endl;cout << "--------------4:后序遍历----------------" << endl;cout << "--------------5:总结点数----------------" << endl;cout << "--------------6:叶子节点数--------------" << endl;cout << "--------------7:树的深度----------------" << endl;cout << "--------------8:树根到叶子的最长路径----" << endl;cout << "--------------9:交换所有节点左右子女----" << endl;cout << "--------------10:顺序存储---------------" << endl;cout << "--------------11:显示顺序存储-----------" << endl;cout << "--------------12:退出测试程序-----------" << endl;cout << "请输入指令编号:" << endl;if(!(cin >> op)){cin.clear();cin.ignore(INT_MAX,'\n');cout << "请输入整数!" << endl;continue;}switch(op){case 1:test1();break;case 2:test2();break;case 3:test3();break;case 4:test4();break;case 5:test5();break;case 6:test6();break;case 7:test7();break;case 8:test8();break;case 9:test9();break;case 10:test10();break;case 11:test11();break;case 12:cout << "测试结束!" << endl;break;default:cout << "请输入正确的指令编号!" << endl;}}return 0;}六、实验数据及处理结果测试用例:1.创建二叉树(二叉链表形式)2.前序遍历3.中序遍历4.后序遍历5.总结点数6.叶子结点数7.树的深度8.树根到叶子的最长路径9.交换所有左右子女10.顺序存储七、思考讨论题或体会或对改进实验的建议通过这次实验,我掌握了二叉树的顺序存储和链式存储,体会了二叉树的存储结构的特性,掌握了二叉树的树上相关操作。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

北京邮电大学软件学院2019-2020学年第1学期实验报告课程名称:算法与数据结构课程设计实验名称:树及其应用实验完成人:日期: 2019 年 11月 10 日一、实验目的树是一种应用极为广泛的数据结构,也是这门课程的重点。

它们的特点在于非线性。

广义表本质上是树结构。

本章实验继续突出了数据结构加操作的程序设计观点,但根据这两种结构的非线性特点,将操作进一步集中在遍历操作上,因为遍历操作是其他众多操作的基础。

遍历逻辑的(或符号形式的)结构,访问动作可是任何操作。

本次实验希望帮助学生熟悉各种存储结构的特征,以及如何应用树结构解决具体问题(即原理与应用的结合)。

二、实验内容必做内容1)二叉树的建立与遍历[问题描述]建立一棵二叉树,并对其进行遍历(先序、中序、后序),打印输出遍历结果。

[基本要求]从键盘接受输入(先序),以二叉链表作为存储结构,建立二叉树(以先序来建立),并采用递归算法对其进行遍历(先序、中序、后序),将遍历结果打印输出。

[测试数据]ABCффDEфGффFффф(其中ф表示空格字符)则输出结果为先序:ABCDEGF中序:CBEGDFA后序:CGBFDBA2)打印二叉树结构[问题描述]按凹入表形式横向打印二叉树结构,即二叉树的根在屏幕的最左边,二叉树的左子树在屏幕的下边,二叉树的右子树在屏幕的上边。

例如:[测试数据]由学生依据软件工程的测试技术自己确定。

注意测试边界数据,如空二叉树。

[实现提示](1)利用RDL遍历方法;(2)利用结点的深度控制横向位置。

选做内容采用非递归算法实现二叉树遍历。

三、实验环境Windows下利用vs 2019完成,语言c++四、实验过程描述首先构造Tree类,内含树的结构体BiTree,以及本实验所要用到的一些操作typedef struct BiTNode{TElemType data;int degree, depth, level; //度,高度,高度差struct BiTNode* lchild, * rchild; /* 左右孩子指针 */}BiTNode, * BiTree;实现相应功能:1、二叉树的建立与遍历构造二叉树:前序构造,先赋值,然后递归构造左子树,递归构造右函数BiTNode* Tree::CreatBiTree(BiTree T) {TElemType ch;cin >> noskipws >> ch; //不跳过空格if (ch == ' ')T = NULL; //输入空格表示空子树else {T = new BiTNode; //分配空间if(!T) //分配失败就退出throw new std::bad_alloc;T->degree = 0; //记录度(T)->data = ch;T->depth++; //度增加T->lchild=CreatBiTree(T->lchild); //递归创建左子树T->rchild=CreatBiTree(T->rchild); //递归创建右子树if (T->lchild != NULL)T->degree++; //有一个孩子度就加一if (T->rchild != NULL)T->degree++;}return T;}销毁二叉树:后序递归销毁左右子树(需要先查找到子树,销毁再销毁父亲树)void Tree::Release(BiTree T) {if (T != NULL) {Release(T->lchild); //递归销毁左子树Release(T->rchild); //递归销毁右子树delete T;}}//前序遍历void Tree::PreOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) { if (T) /* T不空 */{(this->*Visit)(T); /* 先访问根结点 */PreOrderTraverse(T->lchild, Visit); /* 再先序遍历左子树 */PreOrderTraverse(T->rchild, Visit); /* 最后先序遍历右子树 */ }}//中序遍历void Tree::InOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) {if (T){InOrderTraverse(T->lchild, Visit); /* 先中序遍历左子树 */(this->*Visit)(T); /* 再访问根结点 */InOrderTraverse(T->rchild, Visit); /* 最后中序遍历右子树 */ }}//后序遍历void Tree::PostOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) {if (T){PostOrderTraverse(T->lchild, Visit); /* 先中序遍历左子树 */PostOrderTraverse(T->rchild, Visit); /* 最后中序遍历右子树 */(this->*Visit)(T); /* 再访问根结点 */}}//查找深度int Tree::TreeDepth(BiTree T) {int i, j;if (!T)return 0; /* 空树深度为0 */if (T->lchild)i = TreeDepth(T->lchild); /* i为左子树的深度 */elsei = 0;if (T->rchild)j = TreeDepth(T->rchild); /* j为右子树的深度 */elsej = 0;T->depth = i > j ? i + 1 : j + 1;return T->depth;}//得到层数void Tree::getLevel(BiTree T, int level){if (T){T->level = level;getLevel(T->lchild, level + 1); //得到左子树的层数,左子树根节点的层数比此节点多一getLevel(T->rchild, level + 1); //得到右子树的层数,右子树根节点的层数比此节点多一}}//非递归中序遍历void Tree::NoRecInOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) {LinkedStack<BiTree> S;BiTree p = T;while (p || !S.isEmpty()) {if (p) {S.Push(p); //当节点不为空时就压栈,然后判断左孩子p = p->lchild;}else {p=S.Pop(); //返回到父节点(this->*Visit)(p); //访问p = p->rchild; //然后指向右节点}}}实验二:2、打印二叉树结构//中序遍历RDLvoid Tree::InOrderTraverseRDL(BiTree T, void(Tree::* Visit)(BiTree)) {if (T){InOrderTraverseRDL(T->rchild, Visit); /* 先中序遍历左子树 */(this->*Visit)(T); /* 再访问根结点 */InOrderTraverseRDL(T->lchild, Visit); /* 最后中序遍历右子树 */ }}//打印二叉树图形打印图形时,需要中序遍历RDL(先遍历右节点,再遍历右节点)。

每一个字符占一行,所在的列根据此节点的层数来确定。

(void printT(BiTree T) { //打印二叉树图形for (int i = 0; i < T->level; i++) {cout <<" ";}cout <<T->data << endl;}实验3:采用非递归算法实现二叉树遍历利用栈来模拟操作系统调用函数判断该节点是否为空,如果不为空就压栈,否则弹出栈中最上层元素//非递归前序遍历void Tree::NoRecPreOrderTraverse(BiTree T, void(Tree::* Visit)(BiTree)) {LinkedStack<BiTree> S;BiTree p = T;while (p || !S.isEmpty()) {if (p) {(this->*Visit)(p); //先访问S.Push(p);p = p->lchild; //当节点不为空时就压栈,然后判断左孩子}else { //节点为空时p = S.Pop(); //返回到父节点然后指向右节点p = p->rchild;}}}//非递归后序遍历后序遍历时如果当前结点左右子树均为空,则可以访问当前结点,或者左右子树不均为空,但是前一个访问的结点是当前结点的左孩子或者右孩子,则也可以访问当前结点否则则压入栈中。

压栈时先压右节点再压左节点。

void Tree::NoRecPostOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) {LinkedStack<BiTree> S;S.Push(T); //将根节点压栈BiTree pre = NULL; //前一个节点BiTree cur; //现在的节点while (!S.isEmpty()) //如果栈不为空就一直进行{cur = S.Peek(); //观测现在的节点,不弹出if (( cur->lchild==NULL && cur->rchild==NULL ) //左右子树不均为空|| ( pre!=NULL &&( pre== cur->rchild||pre==cur->lchild))) //或前一个访问的结点是当前结点的左孩子或者右孩子,则可以访问{(this->*Visit)(cur);cur = S.Pop(); //弹出此节点pre = cur; //改变现在的pre}else{if (cur->rchild != NULL ){S.Push(cur->rchild); //如果右孩子不为空就压入栈}if ( cur->lchild !=NULL ){S.Push(cur->lchild); //如果左孩子不为空就压入栈}}}}void visitT(BiTree T) { //输出节点上的字符数据cout <<T->data;}五、实验结果:输入两组树,分别进行相关运算,得到如下结果:六、源代码:LinkedStack.h栈的模板类#pragma once#include<exception>template< typename T>struct Node {T data;Node<T>* next;};template< typename T>class LinkedStack{private:Node<T>* top;public:LinkedStack();~LinkedStack();void Push(T);T Pop();T Peek();bool isEmpty();};template< typename T> LinkedStack<T>::LinkedStack() { top = nullptr;}template< typename T> LinkedStack<T>::~LinkedStack() { Node<T>* p = nullptr;while (top){p = top;top = top->next;delete p;}}template< typename T>void LinkedStack<T>::Push(T e) { Node<T>* p = new Node<T>;p->data = e;p->next = top;top = p;}template< typename T>T LinkedStack<T>::Pop() {if (!top)throw - 1; //如果为空则失败Node<T>* p = top;T e = p->data;top = top->next;delete p;p = NULL;return e;}template< typename T>T LinkedStack<T>::Peek() {if (!top)throw - 1; //如果为空则失败T e = top->data;return e;}template< typename T>bool LinkedStack<T>::isEmpty() {return top == nullptr;}Tree.h#pragma once#include<iostream>#include<string>#include"LinkedStack.h"using namespace std;typedef char TElemType;typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */ typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */typedef struct BiTNode{TElemType data;int degree, depth, level; //度,高度,高度差struct BiTNode* lchild, * rchild; /* 左右孩子指针 */}BiTNode, * BiTree;class Tree{private:BiTree root;int rootDepth;BiTNode* CreatBiTree(BiTree T); //构造二叉树void Release(BiTree T); //销毁二叉树void InOrderTraverse(BiTree, void(Tree::*Visit)(BiTree)); //中序遍历void InOrderTraverseRDL(BiTree, void(Tree::* Visit)(BiTree)); //RDL 中序遍历void PostOrderTraverse(BiTree, void(Tree::*Visit)(BiTree));//后序遍历void PreOrderTraverse(BiTree, void(Tree::*Visit)(BiTree));//前序遍历int TreeDepth(BiTree T); //测量树的深度void getLevel(BiTree, int); //测量树的层数(节点所在层数)void NoRecPreOrderTraverse(BiTree, void(Tree::*Visit)(BiTree)); //非递归前序遍历void NoRecInOrderTraverse(BiTree, void(Tree::*Visit)(BiTree));//非递归中序遍历void NoRecPostOrderTraverse(BiTree, void(Tree::*Visit)(BiTree));//非递归后序遍历public:Tree() { //构造函数,调用CreatBiTree()root = NULL;root = CreatBiTree(root);rootDepth = TreeDepth(root);getLevel(root, 1);}~Tree(){ //析构函数Release(root);}void visitT(BiTree T) { //输出节点上的字符数据cout <<T->data;}void printT(BiTree T) { //打印二叉树图形for (int i = 0; i < T->level; i++) {cout <<" ";}cout <<T->data << endl;}//下面的几个函数是为了给外部调用而设计的void PreOrderTraverse(void(Tree::*Visit)(BiTree)) {PreOrderTraverse(root, Visit);}void InOrderTraverse(void(Tree::*Visit)(BiTree)) {InOrderTraverse(root, Visit);}void InOrderTraverseRDL(void(Tree::* Visit)(BiTree)) { InOrderTraverseRDL(root, Visit);}void PostOrderTraverse(void(Tree::*Visit)(BiTree)) { PostOrderTraverse(root, Visit);}void NoRecPreOrderTraverse(void(Tree::*Visit)(BiTree)) { NoRecPreOrderTraverse(root, Visit);}void NoRecInOrderTraverse(void(Tree::*Visit)(BiTree)) { NoRecInOrderTraverse(root, Visit);}void NoRecPostOrderTraverse(void(Tree::*Visit)(BiTree)) { NoRecPostOrderTraverse(root, Visit);}};Tree.cpp#include"Tree.h"//构造二叉树BiTNode* Tree::CreatBiTree(BiTree T) {TElemType ch;cin >> noskipws >> ch; //不跳过空格if (ch == ' ')T = NULL; //输入空格表示空子树else {T = new BiTNode; //分配空间if(!T) //分配失败就退出throw new std::bad_alloc;T->degree = 0; //记录度(T)->data = ch;T->depth++; //度增加T->lchild=CreatBiTree(T->lchild); //递归创建左子树T->rchild=CreatBiTree(T->rchild); //递归创建右子树if (T->lchild != NULL)T->degree++; //有一个孩子度就加一if (T->rchild != NULL)T->degree++;}return T;}//销毁二叉树void Tree::Release(BiTree T) {if (T != NULL) {Release(T->lchild); //递归销毁左子树Release(T->rchild); //递归销毁右子树delete T;}}//前序遍历void Tree::PreOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) { if (T) /* T不空 */{(this->*Visit)(T); /* 先访问根结点 */PreOrderTraverse(T->lchild, Visit); /* 再先序遍历左子树 */PreOrderTraverse(T->rchild, Visit); /* 最后先序遍历右子树 */ }}//中序遍历void Tree::InOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) {if (T){InOrderTraverse(T->lchild, Visit); /* 先中序遍历左子树 */(this->*Visit)(T); /* 再访问根结点 */InOrderTraverse(T->rchild, Visit); /* 最后中序遍历右子树 */ }}//中序遍历RDLvoid Tree::InOrderTraverseRDL(BiTree T, void(Tree::* Visit)(BiTree)) {if (T){InOrderTraverseRDL(T->rchild, Visit); /* 先中序遍历左子树 */(this->*Visit)(T); /* 再访问根结点 */InOrderTraverseRDL(T->lchild, Visit); /* 最后中序遍历右子树 */ }}//后序遍历void Tree::PostOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) {if (T){PostOrderTraverse(T->lchild, Visit); /* 先中序遍历左子树 */PostOrderTraverse(T->rchild, Visit); /* 最后中序遍历右子树 */(this->*Visit)(T); /* 再访问根结点 */}}//查找深度int Tree::TreeDepth(BiTree T) {int i, j;if (!T)return 0; /* 空树深度为0 */if (T->lchild)i = TreeDepth(T->lchild); /* i为左子树的深度 */elsei = 0;if (T->rchild)j = TreeDepth(T->rchild); /* j为右子树的深度 */elsej = 0;T->depth = i > j ? i + 1 : j + 1;return T->depth;}//得到层数void Tree::getLevel(BiTree T, int level){if (T){T->level = level;getLevel(T->lchild, level + 1); //得到左子树的层数,左子树根节点的层数比此节点多一getLevel(T->rchild, level + 1); //得到右子树的层数,右子树根节点的层数比此节点多一}}//非递归前序遍历void Tree::NoRecPreOrderTraverse(BiTree T, void(Tree::* Visit)(BiTree)) {LinkedStack<BiTree> S;BiTree p = T;while (p || !S.isEmpty()) {if (p) {(this->*Visit)(p); //先访问S.Push(p);p = p->lchild; //当节点不为空时就压栈,然后判断左孩子}else {p = S.Pop(); //返回到父节点然后指向右节点p = p->rchild;}}}//非递归中序遍历void Tree::NoRecInOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) {LinkedStack<BiTree> S;BiTree p = T;while (p || !S.isEmpty()) {if (p) {S.Push(p); //当节点不为空时就压栈,然后判断左孩子p = p->lchild;}else {p=S.Pop(); //返回到父节点(this->*Visit)(p); //访问p = p->rchild; //然后指向右节点}}}//非递归后序遍历void Tree::NoRecPostOrderTraverse(BiTree T, void(Tree::*Visit)(BiTree)) {LinkedStack<BiTree> S;S.Push(T); //将根节点压栈BiTree pre = NULL; //前一个节点BiTree cur; //现在的节点while (!S.isEmpty()) //如果栈不为空就一直进行{cur = S.Peek(); //观测现在的节点,不弹出if (( cur->lchild==NULL && cur->rchild==NULL ) //左右子树不均为空|| ( pre!=NULL &&( pre== cur->rchild||pre==cur->lchild))) //或前一个访问的结点是当前结点的左孩子或者右孩子,则可以访问{(this->*Visit)(cur);cur = S.Pop(); //弹出此节点pre = cur; //改变现在的pre}else{if (cur->rchild != NULL ){S.Push(cur->rchild); //如果右孩子不为空就压入栈}if ( cur->lchild !=NULL ){S.Push(cur->lchild); //如果左孩子不为空就压入栈}}}}Main.cpp#include"Tree.h"int main() {cout <<"输入一个树:"<< endl;Tree *a = new Tree();cout <<"前序遍历:"<< endl;a->PreOrderTraverse(&Tree::visitT);cout << endl;cout <<"中序遍历:"<< endl;a->InOrderTraverse(&Tree::visitT);cout << endl;cout <<"后序遍历:"<< endl;a->PostOrderTraverse(&Tree::visitT);cout << endl;cout <<"打印图形:"<< endl;a->InOrderTraverseRDL(&Tree::printT);cout << endl;cout <<"非递归前序遍历:"<< endl;a->NoRecPreOrderTraverse(&Tree::visitT);cout << endl;cout <<"非递归中序遍历:"<< endl;a->NoRecInOrderTraverse(&Tree::visitT);cout << endl;cout <<"非递归后序遍历:"<< endl;a->NoRecPostOrderTraverse(&Tree::visitT);}。

相关文档
最新文档