表达式用二叉树表示(1)

合集下载

全国计算机等级考试二级公共基础之树与二叉树1

全国计算机等级考试二级公共基础之树与二叉树1

全国计算机等级考试二级公共基础之树与二叉树1.6 树与二叉树1.6.1 树的基本概念树是一种简单的非线性结构。

在树这种结构中,所有元素之间的关系具有明显的层次关系。

用图形表示树这种数据结构时,就象自然界中的倒长的树,这种结构就用“树”来命名。

如图:在树结构中,每个结点只有一个前件,称为父结点,没有前件的结点只有一个,称为树的根结点,简称为树的根(如R)。

在树结构中,每一个结点可以有多个后件,它们都称为该结点的子结点。

没有后件的结点称为叶子结点(如W,Z,A ,L,B,N,O,T,H,X)。

在树结构中,一个结点拥有的后件个数称为结点的度(如R的度为4,KPQDEC 结点度均为2)。

树的结点是层次结构,一般按如下原则分层:根结点在第1层;同一个层所有结点的所有子结点都在下一层。

树的最大层次称为树的深度。

如上图中的树深度为4。

R结点有4棵子树,KPQDEC结占各有两棵子树;叶子没有子树。

在计算机中,可以用树结构表示算术运算。

在算术运算中,一个运算符可以有若干个运算对象。

如取正(+)与取负(-)运算符只有一个运算对象,称为单目运算符;加(+)、减(-)、乘(*)、除(/)、乘幂(**)有两个运算对象,称为双目运算符;三元函数f(x,y,z)为 f函数运算符,有三个运算对象,称为三目运算符。

多元函数有多个运算对象称多目运算符。

用树表示算术表达式原则是:(1)表达式中的每一个运算符在树中对应一个结点,称为运算符结点(2)运算符的每一个运算对象在树中为该运算结点的子树(在树中的顺序从左到右)(3)运算对象中的单变量均为叶子结点根据上面原则,可将表达式:a*(b+c/d)+c*h-g*f表示如下的树。

树在计算机中通常用多重链表表示,多重链表的每个结点描述了树中对应结点的信息,每个结点中的链域(指针域)个数随树中该结点的度而定。

1.6.2 二叉树及其基本性质1. 什么是二叉树二叉树是很有用的非线性结构。

它与树结构很相似,树结构的所有术语都可用到二叉树这种结构上。

实验五 二叉树的应用----表达式求值

实验五  二叉树的应用----表达式求值

浙江大学城市学院实验报告课程名称python高级程序设计实验项目名称实验五二叉树的应用----表达式求值实验成绩指导老师(签名)日期一.实验目的和要求1、掌握二叉树的链式存储结构;2、掌握在二叉链表上的二叉树的基本操作;3、掌握二叉树的简单应用----表达式树的操作。

二.实验内容1、在实验四中,已经实现了对一个中缀表达式可以用栈转换成后缀表达式,并可对后缀表达式进行求值计算的方法。

另一种思路是可以利用二叉树建立表达式树,通过对该表达式树进行求值计算,本实验实现:输入一个中缀表达式,建立该表达式的二叉树,然后对该二叉树进行表达式值的计算。

如一个中缀达式(6+2)*5 的二叉树表示为如下所示时,该二叉树的后序遍历62+5*正好就是后缀表达式。

设一般数学表达式的运算符包括+、-、*、/ 四种,当然允许(),且()优先级高。

为方便实现,设定输入的表达式只允许个位整数。

要求设计一个完整的程序,对输入的一个日常的中缀表达式,实现以下功能:⏹建立对应的二叉树⏹输出该二叉树的前序序列、中序序列、后序序列⏹求该二叉树的高度⏹求该二叉树的结点总数⏹求该二叉树的叶子结点数⏹计算该二叉树的表达式值分析:(1)表达式树的构建方法:●构建表达式树的方法之一:直接根据输入的中缀表达式构建对于任意一个算术中缀表达式,都可用二叉树来表示。

表达式对应的二叉树创建后,利用二叉树的遍历等操作,很容易实现二叉树的求值运算。

因此问题的关键就是如何创建表达式树。

对于一个中缀表达式来说,其表达式对应的表达式树中叶子结点均为操作数,分支结点均为运算符。

由于创建的表达式树需要准确的表达运算次序,因此,在扫描表达式创建表达式树的过程中,当遇到运算符时不能直接创建结点,而应将其与前面的运算符进行优先级比较,根据比较结果进行处理。

这种处理方式在实验四中以采用过,可以借助一个运算符栈,来暂存已经扫描到的还未处理的运算符。

根据表达式树与表达式对应关系的递归定义,每两个操作数和一个运算符就可以建立一棵表达式二叉树,而该二叉树又可以作为另一个运算符结点的一棵子树。

树和二叉树的实验报告

树和二叉树的实验报告

《数据结构》实验报告题目: 树和二叉树一、用二叉树来表示代数表达式(一)需求分析输入一个正确的代数表达式, 包括数字和用字母表示的数, 运算符号+ - * / ^ =及括号。

系统根据输入的表达式建立二叉树, 按照先括号里面的后括号外面的, 先乘后除的原则, 每个节点里放一个数字或一个字母或一个操作符, 括号不放在节点里。

分别先序遍历, 中序遍历, 后序遍历此二叉树, 并输出表达式的前缀式, 中缀式和后缀式。

(二)系统设计1.本程序中用到的所有抽象数据类型的定义;typedef struct BiNode //二叉树的存储类型{char s[20];struct BiNode *lchild,*rchild;}BiTNode,*BiTree;2.主程序的流程以及各程序模块之间的层次调用关系, 函数的调用关系图:3. 列出各个功能模块的主要功能及输入输出参数void push(char cc)初始条件: 输入表达式中的某个符号操作结果: 将输入的字符存入buf数组中去BiTree Create_RTree()初始条件: 给出二叉树的定义表达式操作结果:构造二叉树的右子树, 即存储表达式等号右侧的字符组BiTree Create_RootTree()初始条件: 给出二叉树的定义表达式操作结果:构造存储输入表达式的二叉树, 其中左子树存储‘X’, 根节点存储‘:=’void PreOrderTraverse(BiTree T)初始条件: 二叉树T存在操作结果:先序遍历T, 对每个节点调用函数Visit一次且仅一次void InOrderTraverse(BiTree T)初始条件: 二叉树T存在操作结果:中序遍历T, 对每个节点调用函数Visit一次且仅一次void PostOrderTraverse(BiTree T)初始条件: 二叉树T存在操作结果:后序遍历T, 对每个节点调用函数Visit一次且仅一次int main()主函数, 调用各方法, 操作成功后返回0(三)调试分析调试过程中还是出现了一些拼写错误, 经检查后都能及时修正。

二叉树的广义表表示法__概述及解释说明

二叉树的广义表表示法__概述及解释说明

二叉树的广义表表示法概述及解释说明1. 引言1.1 概述二叉树是一种常见的数据结构,在计算机科学中广泛应用。

为了有效地表示和操作二叉树,人们提出了各种表示方法。

其中,二叉树的广义表表示法是一种常用且灵活的方式。

1.2 文章结构本文将首先介绍二叉树的广义表表示法的定义和特点。

然后,我们将详细讨论广义表的表示方法,并解释广义表与二叉树之间的关系。

接下来,我们将介绍如何使用广义表表示方法构建二叉树,并讨论相应的转换方法。

最后,我们将探讨在广义表表示法下如何进行遍历和操作二叉树,并提供相应的实现方法和示例场景。

1.3 目的本文的目标是全面而清晰地介绍二叉树的广义表表示法,使读者对该方法有深入理解。

通过学习本文,读者将能够掌握如何使用广义表表示法构建和操作二叉树,并能够在实际问题中应用相关技巧。

同时,本文还旨在帮助读者提高对数据结构和算法相关知识的理解水平,并培养解决实际问题时分析和抽象的能力。

这样,我们完成了“1. 引言”部分的详细撰写。

2. 二叉树的广义表表示法2.1 定义和特点二叉树是一种常用的数据结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。

二叉树的广义表表示法是一种将二叉树以字符串形式进行表示的方法。

在广义表中,以括号形式将二叉树的节点和子树进行包裹,并使用逗号分隔各个元素。

2.2 广义表的表示方法广义表由以下部分组成:- 括号:用来包裹二叉树的节点和子树。

- 节点值:表示该节点存储的数据值。

- 逗号:用于分隔各个元素。

- 空格:可选,用于提高可读性。

例如,假设有一个二叉树如下所示:```A/ \B C/ \D E```它可以表示为广义表形式为:`(A, (B, (), ()), (C, (D, (), ()), (E, (), ())))`解释上述广义表:- `(A`代表当前节点的值为A。

- `(B, (), ())`代表当前节点的左子节点为空并且右子节点为空。

- `(C, (D, (), ()), (E, (), ()))`代表当前节点的左子节点为D、右子节点为E。

算术表达式(例题)-二叉树

算术表达式(例题)-二叉树

最早提出遍历问题的是对存储在计算机中的表达式求值。

例如:(a+b ×(c-d))-e/f 。

表达式用树形来表示,如图8-11-1所示。

运算符在树中放在非终端结点的位置上,操作数放在叶子结点处。

当我们对此二叉树进行先序、中序和后序遍历后,便可得到表达式的前缀、中缀和后缀书写形式:前缀:-+a*b-cd/ef中缀:a+b*c-d-e/f 后缀:abcd-*+ef/-其中,中缀形式是算术表达式的通常形式,只是没有括号。

在计算机内,使用后缀表达式易于求值。

例1 输入一个算术表达式,判断该表达式是否合法,若不合法,给出错误信息;若合法,则输出合法表达式的表达式树。

【算法分析】表达式不合法有三种情况:①左右括号不匹配;②变量名不合法;③运算符两旁无参与运算的变量或数。

分析表达式树可以看到:表达式的根结点及其子树的根结点为运算符,其在树中的顺序是按运算的先后顺序从后到前,表达树的叶子为参与运算的变量或数。

表达式树如图8-11-2处理时,首先找到运算级别最低的运算符“+”作为根结点,继而确定该根结点的左、右子树结点在表达式串中的范围为a 和(b-c)/d ,再在对应的范围内寻找运算级别最低的运算符作为子树的根结点,直到范围内无运算符,则剩余的变量或数为表达式树的叶子。

【算法步骤】① 设数组ex 存放表达式串的各字符,lt 、rt 作为结点的左右指针,变量left 、right 用于存放每次取字符范围的左、右界。

② 设置左界初值为1;右界初值为串长度。

③ 判断左右括号是否匹配,不匹配则认为输入有错误。

④ 在表达式的左右界范围内寻找运算级别最低的运算符,同时判断运算符两旁有否参与运算的变量或数。

若无,则输入表达式不合法;若有,作为当前子树的根结点,设置左子树指针及其左右界值,设置右子树指针及其左右界值。

⑤ 若表达式在左右界范围内无运算符,则为叶子结点,判断变量名或数是否合法。

⑥ 转④,直到表达式字符取完为止。

数据结构实验二叉树

数据结构实验二叉树

实验六:二叉树及其应用一、实验目的树是数据结构中应用极为广泛的非线性结构,本单元的实验达到熟悉二叉树的存储结构的特性,以及如何应用树结构解决具体问题。

二、问题描述首先,掌握二叉树的各种存储结构和熟悉对二叉树的基本操作。

其次,以二叉树表示算术表达式的基础上,设计一个十进制的四则运算的计算器。

如算术表达式:a+b*(c-d)-e/f三、实验要求如果利用完全二叉树的性质和二叉链表结构建立一棵二叉树,分别计算统计叶子结点的个数。

求二叉树的深度。

十进制的四则运算的计算器可以接收用户来自键盘的输入。

由输入的表达式字符串动态生成算术表达式所对应的二叉树。

自动完成求值运算和输出结果。

四、实验环境PC微机DOS操作系统或Windows 操作系统Turbo C 程序集成环境或Visual C++ 程序集成环境五、实验步骤1、根据二叉树的各种存储结构建立二叉树;2、设计求叶子结点个数算法和树的深度算法;3、根据表达式建立相应的二叉树,生成表达式树的模块;4、根据表达式树,求出表达式值,生成求值模块;5、程序运行效果,测试数据分析算法。

六、测试数据1、输入数据:2.2*(3.1+1.20)-7.5/3正确结果:6.962、输入数据:(1+2)*3+(5+6*7);正确输出:56七、表达式求值由于表达式求值算法较为复杂,所以单独列出来加以分析:1、主要思路:由于操作数是任意的实数,所以必须将原始的中缀表达式中的操作数、操作符以及括号分解出来,并以字符串的形式保存;然后再将其转换为后缀表达式的顺序,后缀表达式可以很容易地利用堆栈计算出表达式的值。

例如有如下的中缀表达式:a+b-c转换成后缀表达式为:ab+c-然后分别按从左到右放入栈中,如果碰到操作符就从栈中弹出两个操作数进行运算,最后再将运算结果放入栈中,依次进行直到表达式结束。

如上述的后缀表达式先将a 和b 放入栈中,然后碰到操作符“+”,则从栈中弹出a 和b 进行a+b 的运算,并将其结果d(假设为d)放入栈中,然后再将c 放入栈中,最后是操作符“-”,所以再弹出d和c 进行d-c 运算,并将其结果再次放入栈中,此时表达式结束,则栈中的元素值就是该表达式最后的运算结果。

二叉树 c语言

二叉树 c语言

二叉树 c语言在计算机科学领域中,树型数据结构是一种非常重要的数据结构,在实际开发中也得到了广泛的应用。

其中,二叉树又是一种非常常见的树型结构。

二叉树在很多情况下都能够提供更好的算法效率,同时也易于理解和实现,因此我们可以通过通过学习和掌握二叉树的特点以及优点,来更好的应用到实际开发中。

一、二叉树的定义二叉树是一种树型结构,树型结构是由节点构成的。

二叉树与一般的树型结构不同,它的每个节点最多只有两个子节点,分别称为左子树和右子树。

它们可以为空或者不为空,其子节点的数量时不固定且没有任何限制的。

二叉树的定义如下:(1)空树是树的一种特殊的状态。

我们可以把它称为二叉树;(2)若不是空树,那么它就是由一个称为根节点(root)的元素和左右两棵分别称为左子树(left subtree)和右子树(right subtree)的二叉树组成。

二、二叉树的特性(1)每个节点最多只有两个子节点,分别称为左子节点和右子节点;(2)左子树和右子树是二叉树;(3)二叉树没有重复的节点。

三、二叉树的应用二叉树是一种非常实用的数据结构,因为它可以模拟很多实际生活中的情况。

例如,我们可以利用二叉树来对某些数据进行分类和排序。

在二叉树的基础上,我们还可以构造二叉堆、哈夫曼树等更高级的数据结构。

除此之外,二叉树还可以应用到程序设计中。

例如,我们可以构造一个二叉树来表示某个程序的控制流,这个程序在执行时可以沿着二叉树的各个节点进行分支和选择,实现不同的功能。

此外,我们还可以利用二叉树来加快某些算法的执行效率,比如二分查找算法等。

四、二叉树的遍历方式对于二叉树的遍历,有三种基本方式,即前序遍历、中序遍历、后序遍历。

它们的遍历顺序不同,因此也得到了不同的称呼。

下面我们来简要介绍一下这三种遍历方式的特点和应用。

(1)前序遍历前序遍历是指首先访问树的根节点,然后按照从左到右的顺序依次遍历左子树和右子树。

前序遍历的应用非常广泛,可以用于生成表达式树、构造二叉树等等。

c语言基于二叉树的表达式求值算法

c语言基于二叉树的表达式求值算法

c语言基于二叉树的表达式求值算法C语言中,基于二叉树的表达式求值算法主要包括两部分:中缀表达式转换为后缀表达式和后缀表达式求值。

1.中缀表达式转换为后缀表达式中缀表达式是我们常见的数学表达方式,例如3 + 4 * 2 - 5。

为了方便计算机求值,我们需要将中缀表达式转换为后缀表达式,也叫做逆波兰表达式。

转换的过程使用栈数据结构来实现。

具体算法如下:1.定义一个栈和一个结果字符串,栈用于存储操作符,结果字符串用于保存后缀表达式。

2.从左到右遍历中缀表达式的每一个字符。

3.如果当前字符是数字,直接将其加入结果字符串。

4.如果当前字符是左括号"(",将其入栈。

5.如果当前字符是右括号")",则依次将栈顶的操作符弹出并加入结果字符串,直到遇到左括号为止,同时将左括号从栈中弹出。

6.如果当前字符是操作符,需要将栈中优先级比当前操作符高或者相等的操作符弹出并加入结果字符串,然后将当前操作符入栈。

7.遍历完所有字符后,将栈中剩余的操作符依次弹出并加入结果字符串。

8.最终结果字符串就是后缀表达式。

例如,对于中缀表达式3 + 4 * 2 - 5,转换为后缀表达式为3 4 2 * + 5 -2.后缀表达式求值后缀表达式求值算法使用栈数据结构来实现。

具体算法如下:1.定义一个栈,用于存储操作数。

2.从左到右遍历后缀表达式的每一个字符。

3.如果当前字符是数字,则将其转换为对应的整数并入栈。

4.如果当前字符是操作符,则从栈中弹出两个操作数,先弹出的作为右操作数,后弹出的作为左操作数,根据操作符进行运算,得到结果后入栈。

5.遍历完所有字符后,栈顶的数字即为最终的结果。

例如,对于后缀表达式3 4 2 * + 5 -,求值的过程如下:1.入栈3。

2.入栈4。

3.入栈2。

4.弹出2和4,计算4 * 2 = 8,将8入栈。

5.弹出8和3,计算3 + 8 = 11,将11入栈。

6.入栈5。

7.弹出5和11,计算11 - 5 = 6,得到最终结果。

简单算术表达式的二叉树的构建和求值

简单算术表达式的二叉树的构建和求值

一、概述二、算术表达式的二叉树表示1. 什么是二叉树2. 算术表达式的二叉树表示方法三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式2. 后缀表达式构建二叉树四、算术表达式二叉树的求值五、应用举例六、总结一、概述在数学和计算机科学中,处理算术表达式是一个常见的问题。

在计算机中,算术表达式通常以中缀、前缀或后缀的形式出现,其中中缀表达式最为常见。

而采用二叉树来表示和求解算术表达式,是一种常见且高效的方法。

二、算术表达式的二叉树表示1. 什么是二叉树二叉树是一种树形数据结构,它的每个节点最多只能有两个子节点,分别是左子节点和右子节点。

二叉树可以为空,也可以是非空的。

2. 算术表达式的二叉树表示方法在二叉树中,每个节点要么是操作符,要么是操作数。

操作符节点的左子节点和右子节点分别表示运算符的两个操作数,而操作数节点则不包含任何子节点。

通过这种方式,可以将算术表达式表示为一个二叉树结构。

三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式为了构建算术表达式的二叉树,首先需要将中缀表达式转换为后缀表达式。

中缀表达式是人们常见的形式,例如"2 + 3 * 5",而后缀表达式则更适合计算机处理,例如"2 3 5 * +"。

将中缀转后缀的算法即为中缀表达式的后缀转换法则。

2. 后缀表达式构建二叉树构建二叉树的过程通常采用栈来辅助完成。

从左到右扫描后缀表达式,对于每个元素,如果是操作数,则入栈;如果是操作符,则弹出栈顶两个元素作为其左右子节点,然后将操作符节点入栈。

最终栈中只剩一个节点,即为构建的二叉树的根节点。

四、算术表达式二叉树的求值算术表达式二叉树的求值是递归进行的。

对于二叉树的每个节点,如果是操作符节点,则递归求解其左右子节点的值,并进行相应的操作;如果是操作数节点,则直接返回其值。

最终得到根节点的值,即为整个算术表达式的值。

五、应用举例以中缀表达式"2 + 3 * 5"为例,首先将其转换为后缀表达式"2 3 5 * +",然后根据后缀表达式构建二叉树,最终求得二叉树的根节点即为算术表达式的值。

【数据结构】二叉树

【数据结构】二叉树

【数据结构】⼆叉树【⼆叉树】 ⼆叉树是最为简单的⼀种树形结构。

所谓树形结构,其特征(部分名词的定义就不明确给出了,毕竟不是学术⽂章。

)在于: 1. 如果是⾮空的树形结构,那么拥有⼀个唯⼀的起始节点称之为root(根节点) 2. 除了根节点外,其他节点都有且仅有⼀个“⽗节点”;除此外这些节点还都可以有0到若⼲个“⼦节点” 3. 树中的所有节点都必须可以通过根节点经过若⼲次后继操作到达 4. 节点之间不会形成循环关系,即任意⼀个节点都不可能从⾃⾝出发,经过不重复的径路再回到⾃⾝。

说明了树形结构内部蕴含着⼀种“序”,但是不是线性表那样的“全序” 5. 从树中的任意两个节点出发获取到的两个任意⼦树,要不两者⽆交集,要不其中⼀者是另⼀者的⼦集 限定到⼆叉树,⼆叉树就是任意⼀个节点⾄多只能有两个⼦节点的树形结构。

也就是说,某个节点的⼦节点数可以是0,1或2。

由于可以有两个⼦节点,所以区别两个⼦节点可以将其分别定义为左⼦节点和右⼦节点。

但是需要注意的是,若⼀个节点只有⼀个⼦节点,那么也必须明确这个⼦节点是左⼦节点还是右⼦节点。

不存在“中⼦节点”或者“单⼦节点”这种表述。

由于上述规则对所有节点都⽣效,所以⼆叉树也是⼀个递归的结构。

事实上,递归就是⼆叉树⼀个⾮常重要的特点,后⾯还会提到很多通过递归的思想来建⽴的例⼦。

对于左⼦节点作为根节点的那颗⼆叉树被称为相对本节点的左⼦树,右⼦树是同理。

■ 基本概念 空树 不包含任何节点的⼆叉树,连根节点也没有 单点树 只包含⼀个根节点的⼆叉树是单点树 ⾄于兄弟关系,⽗⼦关系,长辈后辈关系是⼀⾔既明的就不说了。

树中没有⼦节点的节点被称为树叶(节点),其余的则是分⽀节点。

⼀个节点的⼦节点个数被称为“度数”。

正如上所说,⼆叉树任意节点的度数取值可能是0,1或2。

节点与节点之间存在关联关系,这种关联关系的基本长度是1。

通过⼀个节点经过若⼲个关联关系到达另⼀个节点,经过的这些关联关系合起来被称为⼀个路径。

算术表达式(例题)-二叉树

算术表达式(例题)-二叉树

最早提出遍历问题的是对存储在计算机中的表达式求值。

例如:(a+b ×(c-d))-e/f 。

表达式用树形来表示,如图8-11-1所示。

运算符在树中放在非终端结点的位置上,操作数放在叶子结点处。

当我们对此二叉树进行先序、中序和后序遍历后,便可得到表达式的前缀、中缀和后缀书写形式:前缀:-+a*b-cd/ef中缀:a+b*c-d-e/f 后缀:abcd-*+ef/-其中,中缀形式是算术表达式的通常形式,只是没有括号。

在计算机内,使用后缀表达式易于求值。

例1 输入一个算术表达式,判断该表达式是否合法,若不合法,给出错误信息;若合法,则输出合法表达式的表达式树。

【算法分析】表达式不合法有三种情况:①左右括号不匹配;②变量名不合法;③运算符两旁无参与运算的变量或数。

分析表达式树可以看到:表达式的根结点及其子树的根结点为运算符,其在树中的顺序是按运算的先后顺序从后到前,表达树的叶子为参与运算的变量或数。

表达式树如图8-11-2处理时,首先找到运算级别最低的运算符“+”作为根结点,继而确定该根结点的左、右子树结点在表达式串中的范围为a 和(b-c)/d ,再在对应的范围内寻找运算级别最低的运算符作为子树的根结点,直到范围内无运算符,则剩余的变量或数为表达式树的叶子。

【算法步骤】① 设数组ex 存放表达式串的各字符,lt 、rt 作为结点的左右指针,变量left 、right 用于存放每次取字符范围的左、右界。

② 设置左界初值为1;右界初值为串长度。

③ 判断左右括号是否匹配,不匹配则认为输入有错误。

④ 在表达式的左右界范围内寻找运算级别最低的运算符,同时判断运算符两旁有否参与运算的变量或数。

若无,则输入表达式不合法;若有,作为当前子树的根结点,设置左子树指针及其左右界值,设置右子树指针及其左右界值。

⑤ 若表达式在左右界范围内无运算符,则为叶子结点,判断变量名或数是否合法。

⑥ 转④,直到表达式字符取完为止。

二叉树求解表达式值的代码编写。

二叉树求解表达式值的代码编写。

二叉树求解表达式值的代码编写。

二叉树求解表达式值的代码编写是算法领域中的重要问题之一。

在本文中,我将一步一步解释如何编写这样的代码,并提供一个示例来说明算法的实现过程。

首先,让我们明确一下二叉树求解表达式值的问题。

给定一个二叉树,其中每个节点都是一个运算符或是一个操作数,我们需要计算整个表达式的值。

例如,考虑以下二叉树:*/ \+ -/ \ / \3 24 5在这个例子中,根节点是乘法运算符“*”,左子树是加法运算符“+”,右子树是减法运算符“-”,叶子节点是操作数3,2,4和5。

我们的目标是计算整个表达式的值,即(3+2) * (4-5) = 5 * -1 = -5.在解决这个问题之前,我们首先需要定义二叉树的节点。

每个节点可以表示一个运算符或是一个操作数。

我们可以使用面向对象的思想来实现这个节点类。

以下是一个简单的节点类的示例代码:pythonclass Node:def __init__(self, val):self.val = valself.left = Noneself.right = None在这个示例中,我们定义了一个Node类,它有一个val属性表示节点的值,并有left和right属性表示节点的左子树和右子树。

接下来,我们需要编写一个递归的求解表达式值的函数。

该函数将以一个二叉树节点作为参数,并返回该节点所表示的子树的表达式值。

以下是求解表达式值的函数的示例代码:pythondef evaluate_expression(root):# 如果节点为空,返回0if root is None:return 0# 如果为叶子节点,返回节点的值if root.left is None and root.right is None: return root.val# 递归求解左子树和右子树的表达式值left_value = evaluate_expression(root.left) right_value = evaluate_expression(root.right)# 根据节点的值进行相应的运算if root.val == '+':return left_value + right_valueelif root.val == '-':return left_value - right_valueelif root.val == '*':return left_value * right_valueelif root.val == '/':return left_value / right_valueelse:raise ValueError("Invalid operator")在这个示例中,我们首先检查节点是否为空,如果为空,则返回0。

二叉树的表达式求值

二叉树的表达式求值

⼆叉树的表达式求值问题描述: 输⼊⼀个表达式(表达式中的数均为⼩于10的正整数),利⽤⼆叉树来表⽰该表达数,创建表达式树,然后利⽤⼆叉树的遍历操作求表达式的值。

输⼊要求: 多组数据,每组⼀⾏,以‘=’结尾。

当输⼊只有⼀个‘=’时,输⼊结束。

输出要求: 每组数据输出⼀⾏为表达式的值。

样例: 输⼊样例: 1+2-3*4+(1+2)*3= = 输出样例: 0 思路:分别⽤num 队列来存数,op队列来存运算符。

然后取⼀个运算符为⽗节点,取两个数为⼦结点。

将数叠加后就组成了⼀颗表达式树,然后后序遍历求值即可。

#include<iostream>#include<stack>#include<queue>using namespace std;typedef struct Node* BinTree;typedef BinTree BT;// 1+2-3*4+(1+2)*3=string s;queue<char> num;queue<char> op;struct Node{char Data;BT Left;BT Right;int ans;};int fact(char c) {if (c >= '0' && c <= '9') return1;else return2;}BT createNode(char c){BT p = new Node;p->Data = c;p->Left = p->Right = NULL;if (fact(c) == 1)p->ans = c - '0';elsep->ans = 0;return p;}BT createTree() {BT createTree() {for (int i = 0; i < s.size() - 1; i++) {if(fact(s[i]) == 1) num.push(s[i]);else op.push(s[i]);}BT Head = NULL;int flag = 0; //标记有括号时的情况int sflag = 0; //处理开始时为括号的情况if(s[0] == '(') sflag = 1;while(!op.empty()) {char option;option = op.front(); op.pop();if (option != '(' && option != ')') {BT T = createNode(option);if (option == '+' || option == '-') {if (flag == 0) {if (Head == NULL) {T->Left = createNode(num.front());num.pop();T->Right = createNode(num.front());num.pop();}else {T->Left = Head;T->Right = createNode(num.front());num.pop();}Head = T;}else {if (Head == NULL) {T->Left = createNode(num.front());num.pop();T->Right = createNode(num.front());num.pop();Head = T;}else {T->Left = Head->Right ;Head->Right = T;T->Right = createNode(num.front());num.pop();}}}else if(option == '*' || option == '/') {if (flag == 0) {if(Head == NULL) {T->Left = createNode(num.front());num.pop();T->Right = createNode(num.front());num.pop();Head = T;}else {if(sflag == 1 || Head->Data == '*' || Head->Data == '/') { T->Left = Head;Head = T;T->Right = createNode(num.front());num.pop();sflag =0;sflag =0;}else {T->Left = Head->Right ;Head->Right = T;T->Right = createNode(num.front());num.pop();}}}if (flag == 1) {if(Head == NULL) {T->Left = createNode(num.front());num.pop();T->Right = createNode(num.front());num.pop();Head = T;}else {T->Left = Head->Right; Head->Right= T; T->Right = createNode(num.front());num.pop();}}}}else if (option == '('){flag = 1;//continue;}else if (option == ')'){flag = 0;//continue;}}return Head;}void InorderTraversal_1(BT L){if(L){InorderTraversal_1(L->Left );printf("%d ",L->ans );InorderTraversal_1(L->Right );}}void solve(BT L){if(L){solve(L->Left );solve(L->Right );char option = L->Data ;if (option == '+') L->ans = L->Left->ans + L->Right->ans ;if (option == '-') L->ans = L->Left->ans - L->Right->ans ;if (option == '*') L->ans = L->Left->ans * L->Right->ans ;if (option == '/') L->ans = L->Left->ans / L->Right->ans ;//if(option < '0' || option > '9')// printf("%d %c %d = %d\n", L->Left->ans, option, L->Right->ans, L->ans ); }}}void InorderTraversal_2(BT L){BT T=L;stack<BinTree> s;while(T||!s.empty()){while(T){s.push(T);T=T->Left ;}T=s.top();s.pop();printf("%c ",T->Data );T=T->Right ;}}int main() {while(cin >> s && s[0] != '='){BT H = createTree();//InorderTraversal_2(H);//cout << endl;solve(H);//InorderTraversal_1(H);//cout << endl;cout << H->ans << endl;}} 可能我写的过于复杂,有同学做的⽐较好 。

二叉树

二叉树

例.设结点的权集W ={10,12,4,7,5,18,2},建立一棵 哈夫曼树,并求出其带权路径长度。
5.什么是哈夫编码? 在数据通讯中,经常需要将传送的文字转换成由二进制 字符0,1组成的二进制代码,称之为编码。 如果在编码时考虑字符出现的频率,让出现频率高的字 符采用尽可能短的编码,出现频率低的字符采用稍长的编 码,构造一种不等长编码,则电文的代码就可能更短。哈 夫曼编码是一种用于构造使电文的编码总长最短的编码方 案。 6.求哈夫曼编码的方法 (1)构造哈夫曼树 设需要编码的字符集合为{d1,d2,…,dn},它们在电文 中出现的次数集合为{w1,w2,…,wn},以d1,d2,…, dn作为叶结点,w1,w2,…,wn作为它们的权值,构造 一棵哈夫曼树。
6.Insert操作 二叉树的插入操作与查找操作类似,为了将X插入到树 中,实际上就是先对二叉树进行查找操作。如果找到X,则 什么也不做或做一些“更新”。否则,将X插入到遍历路径 的最后一个节点上。 7.Delete操作 删除操作要比插入操作困难,主要是因为其要考虑的 情况比插入多。 如果要删除的节点是一片树叶,那么可以直接删除。 如果节点有一个儿子,则该节点可以在其父节点调整指针 绕过该节点后被删除。复杂的情况是处理有两个儿子的节 点。一般的删除策略是用其右子树的最小数据代替该节点 的数据并递归地删除那个节点。因为有子树中的最小节点 不可能有左儿子,所以第二次Delete要容易。
例.设有A,B,C,D,E,F 6个数据项,其出现的频度分别 为6、5、4、3、2、1,构造一棵哈夫曼树,并确定它们的 哈夫曼编码。
(2)在哈夫曼树上求叶结点的编码。 规定哈夫曼树中的左分支代表0,右分支代表1,则从根 结点到每个叶结点所经过的路径分支组成的0和1的序列便 为该结点对应字符的编码,上图编码为: A=11;B=01;C=00;D=100;E=1011;F=1010。 在哈夫曼编码树中,树的带权路径长度的含义是各个字 符的码长与其出现次数的乘积之和,也就是电文的代码总 长。采用哈夫曼树构造的编码是一种能使电文代码总长为 最短的、不等长编码。 求哈夫曼编码,实质上就是在已建立的哈夫曼树中,从 叶结点开始,沿结点的双亲链域回退到根结点,每回退一 步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼 码值,由于一个字符的哈夫曼编码是从根结点到相应叶结 点所经过的路径上各分支所组成的0,1序列,因此先得到 的分支代码为所求编码的低位码,后得到的分支代码为所 求编码的高位码。

表达式转表达式二叉树

表达式转表达式二叉树

表达式转表达式⼆叉树表达式树⼆叉树是表达式处理的常⽤⼯具,例如,a+b*(c-d)-e/f可以表⽰成如下所⽰的⼆叉树其中,每个⾮叶⼦节点表⽰⼀个运算符,左⼦树是第⼀个运算数对应的表达式,右⼦树是第⼆个表达式对应的表达式。

每个叶⼦节点都是数。

其在空间利⽤上也⾮常⾼效,节点数等于表达式的长度。

表达式转⼆叉树lrj说⽅法有很多种,下⾯介绍他讲的⼀种:找到“最后计算”的运算符(它是整个表达式树的根),然后递归处理左右两边。

1const int maxn = 1000 + 10;2char str[maxn];3int lch[maxn + 1], rch[maxn + 1]; char op[maxn + 1]; //每个结点的左右⼦结点编号和字符4int nc = 0; //结点数5int build_tree(char* s, int x, int y)6{7int i, c1=-1, c2=-1, p=0;8int u;9if(y-x == 1) //仅⼀个字符,建⽴单独结点10 {11 u = ++nc;12 lch[u] = rch[u] = 0;13 op[u] = s[x];14return u;15 }1617for (i = x; i < y; i++) //寻找根节点的位置18 {19switch (s[i])20 {21case'(': p++; break;22case')': p--; break;23case'+':24case'-': if (!p) c1 = i; break;25case'*':26case'/': if (!p) c2 = i; break;27 }28 }29if (c1 < 0) c1 = c2; //找不到括号外的加减号,就⽤乘除号30if(c1 < 0) return build_tree(s, x+1, y-1); //整个表达式被⼀对括号括起来31 u = ++nc;32 lch[u] = build_tree(s, x, c1);33 rch[u] = build_tree(s, c1+1, y);34 op[u] = s[c1];35return u;36 }前缀式、中缀式、后缀式前缀表达式和后缀表达式分别对应表达式树前序和后序遍历的结果,如果不考虑括号,中缀表达式对应表达式树中序遍历的结果。

【信息技术 】用二叉树排序 —树与二叉树 课件 年教科版(2019)高中信息技术选择性必修1

【信息技术 】用二叉树排序 —树与二叉树 课件 年教科版(2019)高中信息技术选择性必修1
(4)该树 5 个分支节点,7 个叶子节 点。 (5)节点H的层数 3 ,树的深度 4 。
(6)节点B的父节点 A 、兄弟节 点 C、D、孩子节点 E、F。



二叉树的基本概念
二叉树是n(n≥0)个节点的有限集合: ① n = 0时,二叉树是一棵空树。。 ② 当n ≠ 0时,二叉树是由一个根节点(N)和两个互不相交的集合被称为
树的基本概念
定义:是n(n>=0)个节点的有限集合 若n=0,称为空树; 若n>0,则它满足如下两个条件; 1)有且仅有一个特定的称为根的节点; 2)其余节点可分为m(m>=0)个互不相交的有限集合
T1,T2,T3.....Tm,其中每一个集合本身又是一棵树,并称为根的子树。
节点A有 三棵子树
节点B有 两棵子树
树与二叉树
A
B
C
D
E
F
G
H
I

树是一种重要的非线性数据结构, 直观的看,它是数据元素(在树中称 之为节点)按分支关系组织起来的结 构,与自然界的树很像。

日常生活中很多事 物可以用树形图来表 示,如家族族谱、动 物分类等,如图所示

日常生活中很多事 物可以用树形图来表 示,如家族族谱、动 物分类等,如图所示
练一练 二
满二叉树
完全二叉树
完全二叉树
非完全二叉树 非完全二叉树
二叉树的基本遍历
对二叉树各个节点进行访问,即是遍历 操作。
1、前序遍历(根 左 右) 先访问根节点,再访问左子树,最
后访问右子树。
如右图的前序遍历顺序为: A-B-C
1A B2 C
二叉树的基本遍历
2、中序遍历(左 根 右) 先访问左子树,再访问根节点,最

二叉树的遍历

二叉树的遍历

T->rchild= CreatBiTree(); /*构造右子树*/ 扩展先序遍历序列
}
2021/2/21
return (T) ;}
A B Φ D Φ Φ C Φ 17Φ
T
T
T
ch=B
ch=Φ
Λ
T
T= Λ, Creat(T)
ch=A T
A
B creat(T L)
ΛB 返回
creat(T L)
creat(T R)
A
p=p->RChild;
}
2021/2/21
}
top
A
B
C
D
top
B
top
A
A
top
D
A
top
A
top
C
13
top
中序遍历二叉树的非递归算法:
A
void InOrder(BiTree T)
{ InitStack(&S); 相当于top=-1;
p=T;
B
C
while(p!=NULL | | !IsEmpty(S)) 相当于top==-1;
}
后序遍历二叉树的递归算法:
void PostOrder (BiTree T)
{ if(T!=NULL)
{ PostOrder (T->lchild);
PostOrder (T->rchild);
printf(T->data); }
2021/2/21
15
}
先序遍历二叉树的递归算法: void PreOder (BiTree T) { if(T! =NULL){ printf (T->data); PreOrder (T->lchild); PreOrder (T->rchild); } }

利用二叉树求表达式的值

利用二叉树求表达式的值

利⽤⼆叉树求表达式的值利⽤⼆叉树求表达式的值,⾸先要注意表达式中先乘除后加减的运算顺序,所以在建⽴树的过程中,就要将加减尽量作为根节点,最后⼀个加减号作为根节点。

建完树之后是运算过程,采⽤树的后序遍历来运算。

⼆叉树的节点结构,其中值的类型⽤char型struct node{char data;node* left;node* right;};node *CRTree(char s[],int begin,int end){node *p;int k,plus=0,posi;if (begin==end) //只有⼀个字符,构造的是⼀个叶⼦节点{p=(node *)malloc(sizeof(node)); //分配存储空间p->data=s[begin]; //值为s[begin]p->left=NULL;p->right=NULL;return p;}//以下为begin!=end的情况for (k=begin; k<=end; k++)if (s[k]=='+' || s[k]=='-'){plus++;posi=k; //最后⼀个+或-的位置}if (plus==0) //没有+或-的情况(因为若有+、-,前⾯必会执⾏plus++)for (k=begin; k<=end; k++)if (s[k]=='*' || s[k]=='/'){plus++;posi=k;}//以上的处理考虑了优先将+、-放到⼆叉树较⾼的层次上//由于将来计算时,运⽤的是后序遍历的思路//处于较低层的乘除会优先运算//从⽽体现了“先乘除后加减”的运算法则//创建⼀个分⽀节点,⽤检测到的运算符作为节点值if (plus!=0){p=(node *)malloc(sizeof(node));p->data=s[posi]; //节点值是s[posi]p->left=CRTree(s,begin,posi-1); //左⼦树由s[begin]⾄s[posi-1]构成p->right=CRTree(s,posi+1,end); //右⼦树由s[posi+1]到s[end]构成return p;}else//若没有任何运算符,返回NULLreturn NULL;}下⾯是运算过程double Comp(node *b){double v1,v2;if (b==NULL)return0;if (b->left==NULL && b->right==NULL) //叶⼦节点,应该是⼀个数字字符(本项⽬未考虑⾮法表达式)return b->data-'0'; //叶⼦节点直接返回节点值,结点中保存的数字⽤的是字符形式,所以要-'0'v1=Comp(b->left); //先计算左⼦树v2=Comp(b->right); //再计算右⼦树switch(b->data) //将左、右⼦树运算的结果再进⾏运算,运⽤的是后序遍历的思路{case'+':return v1+v2;case'-':return v1-v2;case'*':return v1*v2;case'/':if (v2!=0)return v1/v2;elseabort();}}最后要记得将新建的⼆叉树销毁void DestroyBTNode(node *&b) //销毁⼆叉树{if (b!=NULL){DestroyBTNode(b->left);DestroyBTNode(b->right);free(b);}}。

二叉树的广义表表示法

二叉树的广义表表示法

二叉树的广义表表示法什么是二叉树的广义表表示法二叉树是一种常用的数据结构,用于存储有层次关系的数据。

在二叉树的广义表表示法中,使用一种类似于表达式的方式来表示二叉树的结构,方便我们对二叉树进行操作和理解。

广义表表示法的定义方式在广义表表示法中,一个二叉树可以用一个字符串来表示。

字符串中的每个字符都代表二叉树的一个节点,字符的位置代表节点的位置关系。

具体表达方式如下:1.如果一个字符是空格或者#,表示该节点为空节点。

2.如果一个字符是字母或者数字,表示该字符对应的节点的值。

3.如果一个字符是(,表示这是一个节点的左子树的开始。

4.如果一个字符是),表示这是一个节点的左子树的结束。

5.如果一个字符是,,表示这是一棵树的左右子树的分界。

举例说明下面举一个例子来说明如何使用广义表表示法表示一个二叉树。

假设有如下二叉树:A/ \\B C/ \\D E使用广义表表示法来表示这个二叉树,可以得到如下字符串:A(B,#,#),C(D,#,E)解释一下这个字符串的含义:字符串的第一个字符是A,表示根节点的值是A。

字符串的第二个字符是(,表示接下来是根节点的左子树。

字符串的第三个字符是B,表示根节点的左子树的值是B。

字符串的第四个字符是,,表示根节点的左子树和右子树的分界。

字符串的第五个字符是#,表示根节点的右子树为空节点。

字符串的第六个字符是,,表示根节点的右子树和父节点的右子树的分界。

字符串的第七个字符是(,表示接下来是根节点的右子树。

字符串的第八个字符是D,表示根节点的右子树的值是D。

字符串的第九个字符是,,表示根节点的右子树的左右子树的分界。

字符串的第十个字符是E,表示根节点的右子树的右子树的值是E。

字符串的最后一个字符是),表示根节点的右子树的结束。

通过这个字符串,我们可以很清楚地看出二叉树的结构和节点之间的关系。

广义表表示法的优点广义表表示法具有以下几个优点:1.表达简洁:使用字符串作为表达方式,使得二叉树的结构一目了然。

二叉树表达式

二叉树表达式

二叉树表达式
二叉树表达式是一种用二叉树来表示数学表达式的方法。

在二叉树表达式中,每个节点都代表一个操作符或者操作数。

操作符节点的子节点是它的操作数,而操作数节点没有子节点。

二叉树表达式可以方便地进行表达式的求值和转换。

对于一个二叉树表达式,可以使用中序遍历将其转化为中缀表达式,使用前序遍历将其转化为前缀表达式,使用后序遍历将其转化为后缀表达式。

二叉树表达式的构建可以使用递归或者栈来实现。

递归的方法会将中缀表达式分为左右两个子表达式,然后递归构建左右子树;栈的方法则是维护一个操作符栈和一个操作数栈,根据操作符的优先级来构建二叉树。

在计算机科学中,二叉树表达式的应用非常广泛。

例如,在编译器中,可以将源代码转化为二叉树表达式来进行语法分析和优化。

在计算器中,可以使用二叉树表达式来方便地计算复杂的数学表达式。

- 1 -。

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

数据结构程序报告(3)2011.3.292. 需求分析:(1)功能:表达式可以用二叉树表示,对于简单的四则运算,请实现以下功能【1】对于任意给出的前缀表达式(不带括号)、中缀表达式(可以带括号)或后缀表达式(不带括号),能够在计算机内部构造出一棵表达式二叉树,并且图示出来(图形的形式)。

【2】对于构造好的内部表达式二叉树,按照用户的要求输出相应的前缀表达式(不带括号)、中缀表达式(可以带括号,但不允许冗余括)或后缀表达式(不带括号)。

提示:所谓中缀表达式中的冗余括号,就是去掉括号后不影响表达式的计算顺序。

例如:“(c+b)+a”中的括号是冗余的,可以表示成不冗余的“c+b+a”。

(2)输入输出要求:请输入字符串表达式:树形二叉树(图形显示)中缀表达式为:前缀表达式为:后缀表达式为:3.概要设计:(算法)分成两部分完成:【1】前缀、中缀、后缀表达式->二叉树表达式前缀表达式->二叉树表达式:(a)碰到操作数则把其值赋给相应的新申请的二叉树结点,地址压栈;(b)碰到操作符则把其值赋给相应的新申请的二叉树,并从栈中弹出两个地址,分别作为其右指针和左指针,然后再把其地址压栈,最后一个地址即为二叉树的根结点地址。

中缀表达式->二叉树表达式:把中缀表达式转换成后缀表达式,然后再建立二叉树。

后缀表达式->二叉树表达式:(a)碰到操作数则把其值赋给相应的新申请的二叉树结点,若栈为空则地址压栈,若非空则取栈顶元素,若栈顶元素的左孩子为空则当前结点设为其左孩子,左孩子为满则设为其右孩子再压栈;(b)碰到操作数则把其值赋给相应的新申请的二叉树结点,取栈顶元素,若栈顶元素的左孩子为空则设为其左孩子,左孩子为满则设为其右孩子开始那个元素地址为根结点地址,开始时用变量root保存。

【1】二叉树表达式->前缀、中缀、后缀表达式二叉树表达式->前缀表达式:对二叉树表达式进行前序遍历。

二叉树表达式->中缀表达式:对二叉树表达式进行中序遍历,若结点操作符的优先级高于其左或右子树,在打印相应的子树之前先打印开括号,在打印相应的子树最后在打印一个闭括号。

二叉树表达式->后缀表达式:对二叉树表达式进行后序遍历。

建立表达式树就是建立树中的每一个结点,将每一个结点链接起来就是整棵树。

而在建立深度低的结点时要将其左右指针指向之前建立的深度比它高一级的结点(如’*’要指向’2’和’3’,而’+’又要指向’*’)。

这样我们可以用栈来存放每次建立的结点,按照优先级(表达式为中缀型)或顺序扫描表达式(表达式为波兰式与逆波兰式)建立每一个结点。

建立结点的顺序即为表达式求值的顺序。

如果扫描到操作数则直接新建一个左右指针为空的结点,并压入结点栈中(存放结点指针)。

遇到运算符时首先新建一个结点,然后从栈中依次弹出两个结点,并让新建立的结点的左右指针域指向它们。

当所有结点建立完毕时,如果表达式没有错误(这里假设输入表达式正确),这时栈中应该只剩下一个结点,它就是所建立的表达式的根结点。

4. 详细设计:(具体方法)首先创建一个节点类TNode:包含操作符oper、左孩子left、右孩子right,isOper ()判断是否为操作符,getOperOrder()返回运算符op所对应的优先级,freeTree()程序结束销毁二叉树,postOrder()先序遍历,preOrder()后序遍历,inOrder()中序遍历,ExpTree1()后缀表达式生成二叉树,ExpTree3()前缀表达式生成二叉树,ExpTree2()中后缀表达式生成二叉树,count()求值函数,paint()输出函数附程序:#include <iostream>#include <stack>#include <queue>#include <string>#include<math.h>using namespace std;class TNode//节点类{ public:char oper;TNode *left;TNode *right;int s;int t;TNode(){ left=right=NULL;oper=0;}TNode(char op){ left=right=NULL;oper=op;}};bool isOper(char op)//判断是否为运算符{char oper[]={'(',')','+','-','*','/','^'};for(int i=0;i<sizeof(oper);i++){ if(op==oper[i]){return true;} }return false;}int getOperOrder(char op)//返回运算符op所对应的优先级{ switch(op){ case '(':return 1;case '+':case '-':return 2;case '*':case '/':return 3;case '^':return 4;default://定义在栈中的右括号和栈底字符的优先级最低return 0;} }void freeTree(TNode *&p)//释放树{ if(p->left!=NULL)freeTree(p->left);if(p->right!=NULL)freeTree(p->right);delete(p);cout<<"Memory free "; }void postOrder(TNode *p) //先序遍历{ if(p){ postOrder(p->left);postOrder(p->right);cout<<p->oper;} }void preOrder(TNode *p) //后序遍历{ if(p){ cout<<p->oper;preOrder(p->right);} }void inOrder(TNode *p)//中序遍历{ if(p){ if(p->left){ if(isOper(p->left->oper)&& getOperOrder(p->left->oper)<getOperOrder(p->oper)){ cout<<"(";inOrder(p->left);cout<<")";}else{inOrder(p->left);} }cout<<p->oper;if(p->right){ if(isOper(p->right->oper)&& getOperOrder(p->right->oper)<=getOperOrder(p->oper)){ cout<<"(";cout<<")";}else{inOrder(p->right);} } } }void ExpTree1(TNode *&p,string str)//后缀表达式生成二叉树{stack <TNode*> nodeStack;char temp;int i=0;temp=str[i++];while(temp!='\0'){ if(temp!='\0'&&!isOper(temp))//不是运算符,则进栈{ p=new TNode(temp);//以temp为结点值构造二叉树结点nodeStack.push(p);temp=str[i++];}else{ p=new TNode(temp);if(nodeStack.size()){ p->right=nodeStack.top();//若非空则弹栈并设为结点的右孩子nodeStack.pop(); }if(nodeStack.size()){ p->left=nodeStack.top();//若非空则弹栈并设为结点的左孩子nodeStack.pop(); }nodeStack.push(p);temp=str[i++];} } }void ExpTree3(TNode *&p, string str)//前缀表达式生成二叉树{ stack <TNode*> nodeStack;char temp;int i=str.size()-1;temp=str[i--];while(temp!='\0'){ if(temp!='\0'&&!isOper(temp)){ p=new TNode(temp);//以temp为内容来建立新的结点nodeStack.push(p);temp=str[i--];}else{ p=new TNode(temp);if(nodeStack.size())//若栈顶指针所指结点左孩子为空{ p->left=nodeStack.top(); //则当前结点设置成其左孩子nodeStack.pop();} if(nodeStack.size())//若栈顶指针所指结点右孩子为空{ p->right=nodeStack.top();//则当前结点设置成其右孩子nodeStack.pop();//栈顶元素左右孩子指针设置完毕弹出}nodeStack.push(p);temp=str[i--];} } }void ExpTree2(TNode *&p, string str)//中缀表达式转换成后缀表达式生成二叉树{ stack<char> a;char temp;string Postfixexp="";int i=0;temp=str[i++];while(temp!='\0'){ if(!isOper(temp)){ Postfixexp+=temp;temp=str[i++];}else if(temp=='(')//进栈{ a.push(temp);temp=str[i++];}else if(temp==')'){while(a.top()!='(')//脱括号{ Postfixexp+=a.top();a.pop();//在碰到开括号和栈为空前反复弹出栈中元素}a.pop();temp=str[i++];}else if(temp=='+'||temp=='-'||temp=='*'||temp=='/')//出栈{ while(!a.empty()&&a.top()!='('&&getOperOrder(a.top())>=getOperOrder(tem p))//若栈非空栈顶不是左括号且栈顶元素优先级不低于输入运算符时,//将栈顶元素弹出到后缀表达式中,并且str下标加1{ Postfixexp+=a.top();a.pop(); }a.push(temp);temp=str[i++];} }while(!a.empty()){ Postfixexp+=a.top();a.pop();}ExpTree1(p,Postfixexp); }void count(TNode *p,int &height,int n)//求值函数{ if(p->left==NULL&&p->right==NULL){ if(n>height)height=n;}if(p->left!=NULL)count(p->left,height,n+1);if(p->right!=NULL)count(p->right,height,n+1); } void paint(TNode *p)//输出函数{ int height=0;int h=0;int i;using std::queue;queue<TNode*> aQueue;count(p,height,1);TNode *pointer=p;TNode *lastpointer;if(pointer){ pointer->s=1;pointer->t=1;aQueue.push(pointer); }while(!aQueue.empty()){ lastpointer=pointer;pointer=aQueue.front(); aQueue.pop();if(pointer->s>h){cout<<endl;h=pointer->s;}if(pointer->t==1){for(i=0;i<pow(2,height-pointer->s)-1;i++)cout<<" ";}else if(lastpointer->s!=pointer->s){for(i=0;i<(pointer->t-1)*(pow(2,height-pointer->s+1)-1)+(pointer->t-1)-1+pow(2, height-pointer->s);i++)cout<<" "; }else{ for(i=0;i<(pointer->t-lastpointer->t)*(pow(2,height-pointer->s+1)-1)+(pointer->t -lastpointer->t)-1;i++)cout<<" "; }cout<<pointer->oper;if(pointer->left!=NULL){pointer->left->s=pointer->s+1;pointer->left->t=pointer->t*2-1;aQueue.push(pointer->left);}if(pointer->right!=NULL){pointer->right->s=pointer->s+1;pointer->right->t=pointer->t*2;aQueue.push(pointer->right);} } }int main(){ string expression;TNode *tree;cout<<endl<<"请输入字符串表达式:";cin>>expression;if(isOper(expression[0]))ExpTree3(tree,expression);else if(isOper(expression[1]))ExpTree2(tree,expression);elseExpTree1(tree,expression);paint(tree);cout<<endl;cout<<"中缀表达式为:";inOrder(tree);cout<<endl;cout<<"前缀表达式为:";preOrder(tree);cout<<endl;cout<<"后缀表达式为:";postOrder(tree);cout<<endl;freeTree(tree);cout<<endl;system("pause");return 0; }5.测试数据:(1)请输入字符串表达式:-+1*234-+ 41*2 3中缀表达式为:1+2*3-4前缀表达式为:-+1*234后缀表达式为:123*+4-memory free memory free memory free memory free memory free 请按任意键继续………………………..(2)请输入字符串表达式:1+2*3-4-+ 41*2 3中缀表达式为:1+2*3-4前缀表达式为:-+1*234后缀表达式为:123*+4-memory free memory free memory free memory free memory free请按任意键继续………………………..(3)请输入字符串表达式:123*+4--+ 41*2 3中缀表达式为:1+2*3-4前缀表达式为:-+1*234后缀表达式为:123*+4-memory free memory free memory free memory free memory free请按任意键继续………………………..测试截图:6.总结:程序调试中的问题及解决方法:前缀表达式建树,通过入栈出栈操作求出前缀表达式的逆序,针对得到的逆序表达式通过后缀表达式建立二叉树的方法,遇到操作数则入栈,遇到操作符则从栈中弹出两个操作数构建一棵小的二叉树,然后将小树的根节点入栈以便于下次操作。

相关文档
最新文档