基于二叉树结构的表达式求值算法
实验五 二叉树的应用----表达式求值
浙江大学城市学院实验报告课程名称python高级程序设计实验项目名称实验五二叉树的应用----表达式求值实验成绩指导老师(签名)日期一.实验目的和要求1、掌握二叉树的链式存储结构;2、掌握在二叉链表上的二叉树的基本操作;3、掌握二叉树的简单应用----表达式树的操作。
二.实验内容1、在实验四中,已经实现了对一个中缀表达式可以用栈转换成后缀表达式,并可对后缀表达式进行求值计算的方法。
另一种思路是可以利用二叉树建立表达式树,通过对该表达式树进行求值计算,本实验实现:输入一个中缀表达式,建立该表达式的二叉树,然后对该二叉树进行表达式值的计算。
如一个中缀达式(6+2)*5 的二叉树表示为如下所示时,该二叉树的后序遍历62+5*正好就是后缀表达式。
设一般数学表达式的运算符包括+、-、*、/ 四种,当然允许(),且()优先级高。
为方便实现,设定输入的表达式只允许个位整数。
要求设计一个完整的程序,对输入的一个日常的中缀表达式,实现以下功能:⏹建立对应的二叉树⏹输出该二叉树的前序序列、中序序列、后序序列⏹求该二叉树的高度⏹求该二叉树的结点总数⏹求该二叉树的叶子结点数⏹计算该二叉树的表达式值分析:(1)表达式树的构建方法:●构建表达式树的方法之一:直接根据输入的中缀表达式构建对于任意一个算术中缀表达式,都可用二叉树来表示。
表达式对应的二叉树创建后,利用二叉树的遍历等操作,很容易实现二叉树的求值运算。
因此问题的关键就是如何创建表达式树。
对于一个中缀表达式来说,其表达式对应的表达式树中叶子结点均为操作数,分支结点均为运算符。
由于创建的表达式树需要准确的表达运算次序,因此,在扫描表达式创建表达式树的过程中,当遇到运算符时不能直接创建结点,而应将其与前面的运算符进行优先级比较,根据比较结果进行处理。
这种处理方式在实验四中以采用过,可以借助一个运算符栈,来暂存已经扫描到的还未处理的运算符。
根据表达式树与表达式对应关系的递归定义,每两个操作数和一个运算符就可以建立一棵表达式二叉树,而该二叉树又可以作为另一个运算符结点的一棵子树。
基于二叉树的表达式求值算法实验报告
基于二叉树的表达式求值算法实验报告一、实验目的1. 学习基于二叉树的表达式求值算法。
2. 掌握二叉树的遍历方法和递归算法。
3. 设计并实现基于二叉树的表达式求值程序。
二、实验环境操作系统:Windows 10开发环境:Visual Studio Code 1.57.1编程语言:C++三、算法描述1. 表达式转二叉树将中缀表达式转换为二叉树的过程可以通过递归算法实现。
具体步骤如下:(1)如果表达式只有一个数字,那么将其作为叶子节点返回。
(2)如果表达式包含多个操作符,则以操作符优先级最低的操作符为根节点,将表达式分成两部分,分别递归处理左子树和右子树。
(3)如果表达式中有括号,则将括号中的表达式作为一棵子树递归处理。
2. 表达式求值二叉树求值的过程可以通过递归算法实现。
对于一个二叉树节点,分别计算其左子树和右子树的值,并根据节点的操作符计算节点的值。
具体步骤如下:(1)如果节点是叶子节点,则其值为对应数字。
(2)如果节点是加法节点,则将左右子树的值相加。
(3)如果节点是减法节点,则将左子树的值减去右子树的值。
(4)如果节点是乘法节点,则将左右子树的值相乘。
(5)如果节点是除法节点,则将左子树的值除以右子树的值。
四、实验步骤1. 定义二叉树节点结构体c++struct node {char oper; 节点的操作符double val; 节点的值node* left; 左子树节点node* right; 右子树节点};2. 实现表达式转二叉树函数c++node* expressionToTree(string exp) { int len = exp.length();node* root = NULL;如果表达式是一个数字if (len == 1) {root = new node;root->oper = '#';root->val = exp[0] - '0';root->left = NULL;root->right = NULL;return root;}如果表达式包含多个操作符int pos = 0, priority = 0;for (int i = 0; i < len; i++) {if (exp[i] == '(') {priority += 10;continue;}if (exp[i] == ')') {priority -= 10;continue;}if (exp[i] == '+' exp[i] == '-') {if (priority <= 1) {root = new node;root->oper = exp[i];root->left = expressionT oTree(exp.substr(pos, i - pos));root->right = expressionToTree(exp.substr(i + 1));return root;}}if (exp[i] == '*' exp[i] == '/') {if (priority <= 2) {root = new node;root->oper = exp[i];root->left = expressionT oTree(exp.substr(pos, i - pos));root->right = expressionToTree(exp.substr(i + 1));return root;}}}return root;}3. 实现表达式求值函数c++double evaluate(node* root) {if (root == NULL) return 0.0;if (root->left == NULL && root->right == NULL) return root->val;double left_val = evaluate(root->left), right_val =evaluate(root->right);switch (root->oper) {case '+': return left_val + right_val;case '-': return left_val - right_val;case '*': return left_val * right_val;case '/': return left_val / right_val;default: return 0.0;}}4. 测试程序c++int main() {string exp = "((5-2)*(3+4))/7";node* root = expressionToTree(exp);cout << exp << " = " << evaluate(root) << endl; 输出结果为3 return 0;}五、实验结果分析本实验设计并实现了基于二叉树的表达式求值程序。
基于二叉树的算术表达式计算与实现
&x ) Is ) {
it p s = 0z n o l B N T o d e { 1c h ild =
gt o et+x l ps) e d(r is , O1; N s ) B N e* o T O r t= gt oe t ps, d o e d (r ol N s+ I s) x 1; )
d t SrCU ,t r r e o sl i s f r c n et g aa tU tr e e h e ae sl m o t n o ov r i d uo n
a i me i e pes n t b a y t e . T i p p r d c s s r h t x rs 0 i re t c  ̄ n r h a e i us s s e
/^\ \
() +2 -)4 b 5 ( 32
igtr ryro- ot f e i i ( t > pr ( P ot o ) > gtr fyn e > pr e ii (o - ot) P ot d ) {
n o d e — — >lhl =r o ; c id o t n o d e — —
{ p s+ 1 o = ;
基于二叉树的算术表达 式计算 与实现
E a u to f a i me i e p e so a e n b n r r e v l a in o r h t t c x r s i n b s d o i a y te
r u n NU L e r L ; t } eefc= \ ’ IUT NU L l ( =’0)  ̄ I L ; s h L I
/^ \
1 + 1 1
/\
r5 i 女
w i( oe gt oe t ps ,I1 hl(d = e d (r olp S en N s+ 3 ) ) ) {
二叉树表达式求值
switch(str1)
{
case '#':case'(':case'[':return 0;break;
case '*':case '/':return 1;break;
case '+':case'-':switch(str2)
{
case '+':case'-':case'#':return 1;break;
}
pushstack1(L1,p[i]);
break;
}
}
i++;
}
popstack2(L2,T);
return T;
}
//后序遍历表达式树
void postorder(BiTree T)
{
if(T)
{
postorder(T->lchild);
printf("后缀式为:");
postorder(T);
printf("\n");
printf("前缀式为");
midorder(T);
printf("\n");
printf("结果为:");
printf("%.3f\n",T->data2);
}
{
while(indigit(p[i]))
{
str[j++]=p[i];
i++;
二叉树计算表达式
二叉树计算表达式计算表达式是计算机科学中常见的任务,而二叉树是一种常用的数据结构,用于表示表达式。
本文将介绍二叉树如何表示和计算表达式。
一、二叉树表示表达式二叉树是由节点和边组成的树状结构。
每个节点都包含一个值和两个指向左右子节点的指针。
二叉树可以用来表示数学表达式。
例如,下面是一个包含加、减、乘、除的表达式:```5 + 3 *6 / 2 - 4```将表达式转化为二叉树表示,根节点为`-`,其左子树是`+`,右子树是`4`。
`+`节点的左子树为`5`,右子树为`/`。
`/`节点的左子树为`*`,右子树为`2`。
`*`节点的左子树为`3`,右子树为`6`。
```-/ \+ 4/ \5 // \* 2/ \3 6```每个节点的值表示该节点的操作符或操作数。
叶子节点是操作数,内部节点是操作符。
二、计算二叉树表达式计算表达式需要递归地对二叉树进行遍历。
从根节点开始,如果是操作符节点,就对其左右子节点进行递归。
如果是操作数节点,就返回该节点的值。
等到递归完成后,就可以根据操作符节点的值和左右子节点的值对表达式进行计算了。
对于上面的表达式二叉树,计算的过程如下。
首先计算根节点的左右子节点,即`+`节点和`4`节点的值。
`+`节点还需要计算其左右子节点`5`和`/`节点的值。
`/`节点又需要计算其左右子节点`*`和`2`的值。
`*`节点需要计算其左右子节点`3`和`6`的值。
归纳起来,计算的顺序是从下到上,从左到右。
```-/ \+ 4/ \5 // \* 2/ \3 6```按照计算顺序求值:1. 计算`3 * 6`,得到18。
2. 计算`6 / 2`,得到3。
3. 计算`3 / 3`,得到1。
4. 计算`5 + 1`,得到6。
5. 计算`6 - 4`,得到2。
因此,表达式`5 + 3 * 6 / 2 - 4`的值是2。
三、扩展上面的例子说明了如何将表达式转为二叉树,并计算表达式的值。
但实际中会有更复杂的表达式,如函数调用、变量引用等。
完全二叉树的总结点数公式
完全二叉树的总结点数公式在解决完全二叉树问题时,有一个重要的公式可以帮助我们计算完全二叉树的总结点数。
根据完全二叉树的特性,我们可以通过判断左子树或右子树的高度来确定完全二叉树是满二叉树还是完全二叉树,并利用递归的方式计算总结点数。
下面是完全二叉树总结点数的公式:若完全二叉树的高度为h,根节点的高度为0,那么:-如果左子树的高度等于右子树的高度(即完全二叉树是满二叉树),则左子树为高度为h-1的满二叉树,其总结点数为2^(h-1)-1,右子树为高度为h-2的完全二叉树,其总结点数可以通过递归的方式计算。
-如果左子树的高度大于右子树的高度(即完全二叉树不是满二叉树),则右子树为高度为h-1的满二叉树,其总结点数为2^(h-2)-1,左子树为高度为h-1的完全二叉树,其总结点数可以通过递归的方式计算。
具体地,我们可以通过以下步骤来计算完全二叉树的总结点数:1.对于给定的完全二叉树,首先计算树的高度h。
可以从根节点开始,通过逐层遍历左子树来计算。
2.判断左子树和右子树的高度是否相等。
如果相等,表示完全二叉树是满二叉树,根据上述公式计算左子树和右子树的总结点数。
3.如果左子树的高度大于右子树的高度,表示完全二叉树不是满二叉树,根据上述公式计算左子树和右子树的总结点数。
4.将左子树和右子树的总结点数相加,并加上根节点,即得到完全二叉树的总结点数。
下面是一个具体的例子来说明完全二叉树的总结点数公式:```/\23/\/\4567```对于上述的完全二叉树,根节点的高度为0,左子树的高度为1,右子树的高度为2、因此,左子树为高度为1的完全二叉树,其总结点数为2^1-1=1,右子树为高度为2的完全二叉树,其总结点数为2^2-1=3、将左子树和右子树的总结点数相加,并加上根节点,即1+3+1=5,所以该完全二叉树的总结点数为5综上所述,完全二叉树的总结点数公式为根据完全二叉树的特性来判断树是满二叉树还是完全二叉树,并利用递归的方式计算总结点数。
数据结构实验二叉树
实验六:二叉树及其应用一、实验目的树是数据结构中应用极为广泛的非线性结构,本单元的实验达到熟悉二叉树的存储结构的特性,以及如何应用树结构解决具体问题。
二、问题描述首先,掌握二叉树的各种存储结构和熟悉对二叉树的基本操作。
其次,以二叉树表示算术表达式的基础上,设计一个十进制的四则运算的计算器。
如算术表达式: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 运算,并将其结果再次放入栈中,此时表达式结束,则栈中的元素值就是该表达式最后的运算结果。
二叉链表求算数表达式
二叉链表求算数表达式二叉链表是一种常见的数据结构,用于表示二叉树。
在算术表达式求值中,也可以利用二叉链表来表示算术表达式的结构,方便进行计算和操作。
二叉链表表示算术表达式的方式是将表达式转化为二叉树的形式。
其中,二叉树的叶子节点存储操作数,内部节点存储运算符。
通过遍历二叉树,可以按照特定的规则解释算术表达式并求值。
下面是一个示例,展示如何将算术表达式转化为二叉链表:算术表达式: 2 + 3 * 41. 将运算符和操作数转化为节点,并建立二叉链表:```+/ \2 */ \3 4```2. 通过遍历二叉链表,按照运算符的优先级求值。
首先,遍历左子树进行运算,得到:2然后,遍历右子树进行运算,得到:3 * 4 = 12最后,根据根节点的运算符进行运算,得到:2 + 12 = 14算术表达式的求值过程可以通过二叉链表的先序遍历来实现,具体步骤如下:1. 如果节点是叶子节点(操作数),返回操作数的值。
2. 如果节点是内部节点(运算符),获取左子树和右子树的值。
3. 根据运算符进行相应的运算,并返回结果。
示例的先序遍历过程如下:先序遍历:+ 2 * 3 41. 访问根节点:+2. 访问左子树:23. 访问右子树的左子树:*4. 访问右子树的左子树:35. 访问右子树的右子树:4经过先序遍历的过程,可以逐步解释算术表达式并求值。
二叉链表表示算术表达式的方法在编译原理中得到了广泛的应用。
通过将表达式转化为二叉树的形式,可以方便地进行运算和求值。
在实际应用中,可以使用栈来实现二叉链表表示的算术表达式的求值,具体步骤如下:1. 遍历表达式的每个字符。
2. 如果字符是操作数,将其转化为节点并入栈。
3. 如果字符是运算符,取栈顶的两个节点作为右子树和左子树,将运算符作为根节点,再入栈。
4. 最终栈中只会剩下一个节点,即根节点。
通过这种方式,可以将表达式转化为二叉链表,并计算出最终的结果。
总结起来,二叉链表可以用来表示算术表达式的结构,并进行求值。
后序遍历二叉树实现表达式求值
表达式求值是数据结构 中常见的问题 , 传统的求值方法效率较低. 本文 以逻辑运算为例 , 采用 二叉树 作为表达式的存储结构… , 对二叉树进行后序遍历来实现表达式求值 , 提高了运算效率. 尤其适用于对 同
一
表 达式 中的变 量赋 予 多组 不 同初值 的情 况 , 比如判 断 表达 式 的 类 型 、 求 解 表 达 式 的成 真 赋值 等 , 从 而 可
扩展 应用 到 逻辑 问题 解决 方 案 的求解 等 领域 中.
1 算法设计
运用 二叉 树 实现 表达 式求 值 需解 决 两 个 大 问题 : 表 达 式 的存 储 与 表 达式 求 值 . 本 文 约定 以逻 辑 运 算 为例 , 分别 用 “ &” 、 “ I ” 、 “一” 表示与、 或、 非 三种 逻辑 运算 . 第一 , 表 达式 存储 算 法设计 . 表 1 算符优先关系表
0 1
0 0
O 1
Байду номын сангаас
为“ 与” 运算的运算规则 , 其他运算类似. ( 2 ) 表达式求值.
求值 过程 中只需建 立一个 存放 操作 数 的栈 即可 . 首先 应 该 明确 一 点 : 在存 储 了表 达式 的二叉 树 中 , 操 作 数都 是 叶子结点 , 运算 符都 是分 支结 点. 后 序遍 历该 二叉 树 , 遵循“ 左~ 右一 中” 的顺 序访 问二叉 树 的各
收 稿 日期 : 2 0 1 4 . 1 1 — 1 3
作 者简介 : 潘风 ( 1 9 8 l 一) , 女, 黑龙 江黑 河人 , 运城学 院计 算机科 学与 技术 系讲师 , 工学 硕士 , 主要 从事 网络技术 及应用 方
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,得到最终结果。
利用二叉树求表达式的值
利⽤⼆叉树求表达式的值利⽤⼆叉树求表达式的值,⾸先要注意表达式中先乘除后加减的运算顺序,所以在建⽴树的过程中,就要将加减尽量作为根节点,最后⼀个加减号作为根节点。
建完树之后是运算过程,采⽤树的后序遍历来运算。
⼆叉树的节点结构,其中值的类型⽤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. 算术表达式的二叉树表示方法三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式2. 后缀表达式构建二叉树四、算术表达式二叉树的求值五、应用举例六、总结一、概述在数学和计算机科学中,处理算术表达式是一个常见的问题。
在计算机中,算术表达式通常以中缀、前缀或后缀的形式出现,其中中缀表达式最为常见。
而采用二叉树来表示和求解算术表达式,是一种常见且高效的方法。
二、算术表达式的二叉树表示1. 什么是二叉树二叉树是一种树形数据结构,它的每个节点最多只能有两个子节点,分别是左子节点和右子节点。
二叉树可以为空,也可以是非空的。
2. 算术表达式的二叉树表示方法在二叉树中,每个节点要么是操作符,要么是操作数。
操作符节点的左子节点和右子节点分别表示运算符的两个操作数,而操作数节点则不包含任何子节点。
通过这种方式,可以将算术表达式表示为一个二叉树结构。
三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式为了构建算术表达式的二叉树,首先需要将中缀表达式转换为后缀表达式。
中缀表达式是人们常见的形式,例如"2 + 3 * 5",而后缀表达式则更适合计算机处理,例如"2 3 5 * +"。
将中缀转后缀的算法即为中缀表达式的后缀转换法则。
2. 后缀表达式构建二叉树构建二叉树的过程通常采用栈来辅助完成。
从左到右扫描后缀表达式,对于每个元素,如果是操作数,则入栈;如果是操作符,则弹出栈顶两个元素作为其左右子节点,然后将操作符节点入栈。
最终栈中只剩一个节点,即为构建的二叉树的根节点。
四、算术表达式二叉树的求值算术表达式二叉树的求值是递归进行的。
对于二叉树的每个节点,如果是操作符节点,则递归求解其左右子节点的值,并进行相应的操作;如果是操作数节点,则直接返回其值。
最终得到根节点的值,即为整个算术表达式的值。
五、应用举例以中缀表达式"2 + 3 * 5"为例,首先将其转换为后缀表达式"2 3 5 * +",然后根据后缀表达式构建二叉树,最终求得二叉树的根节点即为算术表达式的值。
二叉树基本运算算法的实现
二叉树基本运算算法的实现
二叉树是一种常见的数据结构,基本运算算法包括二叉树的遍历、查找、插入、删除等操作。
下面是这些算法的实现:
1. 二叉树遍历:二叉树遍历有三种方式,分别是前序遍历、中序遍历和后序遍历。
其中,前序遍历先访问根节点,再访问左子树和右子树;中序遍历先访问左子树,再访问根节点和右子树;后序遍历先访问左子树,再访问右子树和根节点。
遍历可以使用递归算法或栈实现。
2. 二叉树查找:二叉树查找可以使用递归算法或循环算法实现。
递归算法通过比较节点值实现查找,如果查找值小于当前节点值,则在左子树中查找,否则在右子树中查找。
循环算法使用二叉树的特性,比较查找值和当前节点值的大小,根据大小关系不断移动到左子树或右子树中进行查找,直到找到目标节点或遍历到叶子节点为止。
3. 二叉树插入:二叉树插入需要先查找到插入位置,然后在该位置插入一个新节点。
插入操作可以使用递归算法或循环算法实现。
4. 二叉树删除:二叉树删除分为三种情况:删除叶子节点、删除只有一个孩子的节点和删除有两个孩子的节点。
删除叶子节点很简单,只需要将其父节点的指针设为NULL即可。
删除只有一个孩子的节点需要将父节点的指针指向该节点的
孩子节点。
删除有两个孩子的节点需要找到该节点的后继节点(或前驱节点),将后继节点的值复制到该节点中,然后删除后继节点。
上述算法的实现需要根据具体的编程语言进行调整和实现。
数据结构树与二叉树常用计算公式
数据结构树与⼆叉树常⽤计算公式在⼆叉树的理论推导以及⼀些⾼频类型题中,我们经常需要计算⼆叉树的总结点数,某⼀层的结点数以及已知结点数反推树的⾼度,本⽂围绕这⼏个⾼频知识点,归纳总结以下公式。
公式(1)⾮空⼆叉树叶⼦结点数 = 度为2的结点数 + 1 即,N0=N2+1(2)⾮空⼆叉树上第K层⾄多有2k−1个结点(K≥1)(3)⾼度为H的⼆叉树⾄多有2H−1 个结点(H≥1)(4)具有N个(N>0)结点的完全⼆叉树的⾼度为⌈log2(N+1)⌉或⌊log2N⌋+1(5)对完全⼆叉树按从上到下、从左到右的顺序依次编号1,2,...,N,则有以下关系:①当i>1 时,结点i的双亲结点编号为⌊i/2⌋,即当i为偶数时,其双亲结点的编号为i/2 ,它是双亲结点的左孩⼦;当i为奇数时,其双亲结点的编号为 (i−1)/2 ,它是双亲结点的右孩⼦。
②当 2i≤N时,结点i的左孩⼦编号为 2i,否则⽆左孩⼦。
③当 2i+1≤N时,结点i的右孩⼦编号为 2i+1 ,否则⽆右孩⼦。
④结点i所在层次(深度)为⌊log2i⌋+1 。
(设根结点为第1层)经典例题**408考研-2011-4** 若⼀棵完全⼆叉树有768个结点,则⼆叉树中叶结点的个数是_____。
A.257B.258C.384D.385解法1根据完全⼆叉树的性质,最后⼀个分⽀结点的序号为⌊n/2⌋=⌊768/2⌋=384 ,故叶⼦结点的个数为 768−384=384解法2由⼆叉树的性质N=N0+N1+N2和N0=N2+1 可知N=2N0−1+N1,2N0−1+N1=768显然,N1=1,2N0=768,则N0=384解法3完全⼆叉树的叶⼦结点只可能出现在最下两层,由题可计算完全⼆叉树的⾼度为10。
第10层的叶⼦结点数为 768−(29−1)=257第10层的叶⼦结点在第9层共有⌈257/2⌉=129 个⽗节点第9层的叶⼦结点数为 (29−1)−129=127则叶⼦结点总数为 257+127=384Processing math: 100%。
二叉树各种计算公式总结
二叉树各种计算公式总结二叉树是一种常见的数据结构,它由一个根节点和最多两个子节点组成。
许多计算问题可以通过对二叉树进行各种操作和遍历来解决。
在本文中,将总结二叉树的各种计算公式。
1.二叉树节点个数:二叉树节点个数的计算公式是N=N1+N2+1,其中N表示二叉树的节点个数,N1表示左子树的节点个数,N2表示右子树的节点个数。
2. 二叉树的高度:二叉树的高度是指从根节点到最远叶子节点的最长路径上的节点数量。
计算二叉树的高度的公式是H = max(H1, H2) + 1,其中H表示二叉树的高度,H1表示左子树的高度,H2表示右子树的高度。
3.二叉树的深度:二叉树的深度是指从根节点到当前节点的路径的长度。
计算二叉树的深度的公式是D=D1+1,其中D表示二叉树的深度,D1表示父节点的深度。
4.二叉查找树:二叉查找树是一种有序二叉树,它要求对于树中的每个节点,左子树的值都小于节点的值,右子树的值都大于节点的值。
在二叉查找树中进行的公式是:-如果目标值等于当前节点的值,则返回当前节点;-如果目标值小于当前节点的值,则在左子树中继续;-如果目标值大于当前节点的值,则在右子树中继续。
5.二叉树的遍历:二叉树的遍历是指按照一定的顺序访问二叉树中的所有节点。
常见的二叉树遍历方式有三种:- 前序遍历:先访问根节点,然后递归地访问左子树,最后递归地访问右子树。
可以表示为:root -> 左子树 -> 右子树。
- 中序遍历:先递归地访问左子树,然后访问根节点,最后递归地访问右子树。
可以表示为:左子树 -> root -> 右子树。
- 后序遍历:先递归地访问左子树,然后递归地访问右子树,最后访问根节点。
可以表示为:左子树 -> 右子树 -> root。
6.二叉树的最大路径和:二叉树的最大路径和是指二叉树中两个节点之间路径上的节点值的最大和。
可以通过递归地计算每个子树的最大路径和,然后选择最大的子树路径和来得出最终结果。
二叉树的表达式求值
⼆叉树的表达式求值问题描述: 输⼊⼀个表达式(表达式中的数均为⼩于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;}} 可能我写的过于复杂,有同学做的⽐较好 。
数据结构实验报告——四则运算表达式求值
数据结构实验报告——四则运算表达式求值实验五四则运算表达式求值一.问题描述:四则运算表达式求值,将四则运算表达式用中缀表达式,然后转换为后缀表达式,并计算结果。
二.基本要求:使用二叉树来实现。
三.实现提示:利用二叉树后序遍历来实现表达式的转换,同时可以使用实验二的结果来求解后缀表达式的值。
输入输出格式:输入:在字符界面上输入一个中缀表达式,回车表示结束。
输出:如果该中缀表达式正确,那么在字符界面上输出其后缀表达式,其中后缀表达式中两相邻操作数之间利用空格隔开;如果不正确,在字符界面上输出表达式错误提示。
测试实例:输入:21+23* (12-6 )输出:21 23 12 6 -*+四.设计概要用二叉树表示表达式:若表达式为数或简单变量,则相应二叉树中仅有一个根结点,其数据域存放该表达式信息若表达式= (第一操作数)(运算符)(第二操作数),则相应的二叉树中以左子树表示第一操作数,右子树表示第二操作数,根结点的数据域存放运算符(若为一元算符,则左子树空)。
操作数本身又为表达式.后缀遍历二叉树码实现和静态检查上机调试及测试数据的调试五.源程序:#include#include#include#include#include#include#define STACK_INIT_SIZE 100#define DATA_SIZE 10#define STACKINCREMENT 10#define OK 1#define TRUE 1#define FALSE 0#define ERROR 0#define OVERFLOW -2using namespace std;typedef float SElemtype;typedef int Status;typedef char * TElemType;typedef struct BiTNode {TElemType data;int len; //data字符串中字符的个数struct BiTNode * lchild, * rchild;}BiTNode, *BiTree;typedef struct{SElemtype *base;SElemtype *top;int stacksize;} SqStack;Status IsDigital(char ch)if(ch>='0'&&ch<='9'){return 1; //是数字字母}return 0; //不是数字字母}int CrtNode(stack &PTR, char *c){BiTNode * T;int i=0;T = (BiTNode *)malloc(sizeof(BiTNode));T->data = (char *)malloc(DATA_SIZE*sizeof(char));while(IsDigital(c[i])){T->data [i] = c[i];i++;}T->len = i;T->lchild = T->rchild = NULL;PTR.push (T);return i;}void CrtSubTree(stack &PTR, char c){BiTNode * T;T = (BiTNode *)malloc(sizeof(BiTNode));T->data = (char *)malloc(DATA_SIZE*sizeof(char));T->data [0] = c;T->len = 1;T->rchild = PTR.top(); //先右子树,否则运算次序反了PTR.pop ();T->lchild = PTR.top();PTR.pop ();PTR.push (T);}char symbol[5][5]={{'>', '>', '<', '<', '>'}, //符号优先级{'>', '>', '<', '<', '>'},{'>', '>', '>', '>', '>'},{'>', '>', '>', '>', '>'},{'<', '<', '<', '<', '='}};int sym2num(char s) //返回符号对应优先级矩阵位置{switch(s){case '+': return 0; break;case '-': return 1; break;case '*': return 2; break;case '/': return 3; break;case '#': return 4; break;}}char Precede(char a, char b) //返回符号优先级{return(symbol[sym2num(a)][sym2num(b)]);void CrtExptree(BiTree &T, char exp[]){//根据字符串exp的内容构建表达式树Tstack PTR;//存放表达式树中的节点指针stack OPTR;//存放操作符char op;int i=0;OPTR.push ('#');op = OPTR.top();while( !((exp[i]=='#') && (OPTR.top()=='#')) ) //与{ if (IsDigital(exp[i])){//建立叶子节点并入栈PTRi+=CrtNode(PTR, &exp[i]);}else if (exp[i] == ' ')i++;else{switch (exp[i]){case '(': {OPTR.push (exp[i]);i++;break;}case ')': {op = OPTR.top (); OPTR.pop ();while(op!='('){CrtSubTree(PTR, op);op = OPTR.top (); OPTR.pop ();}//end whilei++;break;}default: //exp[i]是+ - * /while(! OPTR.empty ()){op = OPTR.top ();if (Precede(op, exp[i])=='>'){CrtSubTree(PTR, op);OPTR.pop ();}if(exp[i]!='#'){OPTR.push (exp[i]);i++;}break;}}//end switch}//end else}//end whileT = PTR.top();PTR.pop ();}void PostOrderTraverse(BiTree &T, char * exp ,int &count){//后序遍历表达式树T,获取树中每个结点的数据值生成逆波兰表达式exp //T是表达式树的根节点;字符串exp保存逆波兰表达式;count保存exp中字符的个数//后序遍历中,处理根结点时,依据T->len的值,把T->data中的字符依次添加到当前exp字符串的尾端//添加完T->data后,再添加一个空格字符,同时更新count计数器的值。
基于二叉树的表达式求值算法
基于二叉树的表达式求值算法二叉树的表达式求值算法可以使用递归来实现,具体步骤如下:1. 若该节点为数字节点,则直接返回节点的值;2. 若该节点为操作符节点,则递归计算其左右子树的值,并根据操作符进行计算,最终返回计算结果。
所以,我们可以先构建一个二叉树,然后对二叉树进行递归遍历,实现表达式的求值。
具体实现如下:pythonclass TreeNode:def __init__(self, val):self.val = valself.left = Noneself.right = Nonedef evaluate(root: TreeNode) -> int:"""对二叉树进行递归遍历,实现表达式的求值"""# 如果当前节点为数字,直接返回节点的值if not root.left and not root.right:return int(root.val)# 递归计算左子树的值和右子树的值left_val = evaluate(root.left)right_val = evaluate(root.right)# 根据运算符计算当前节点的值if root.val == '+':return left_val + right_valelif root.val == '-':return left_val - right_valelif root.val == '*':return left_val * right_valelse:return left_val right_val这里假设输入的二叉树是合法的,即括号、运算符和操作数的顺序都正确,不需要进行错误处理。
二叉树求解表达式代码编写 -回复
二叉树求解表达式代码编写-回复如何使用二叉树求解表达式。
引言:在计算机科学中,表达式求解是一项非常基本且重要的任务。
通过将表达式转换为计算机能够理解和处理的形式,我们可以利用计算机来自动求解各种表达式。
在本文中,我们将介绍如何使用二叉树来求解表达式,详细解释每个步骤,并提供相关的代码示例。
一、表达式的构成和表示方法在开始之前,让我们先了解一下表达式的构成和常见的表示方法。
表达式由运算符和操作数组成,运算符用于指定操作数之间的运算关系。
常见的运算符包括加法、减法、乘法、除法等。
表达式通常以中缀表示法展示,即运算符出现在操作数之间。
例如,表达式"3 + 4" 中的运算符是"+",操作数是3 和4。
二、二叉树表示方法为了方便表达式的求解,我们可以将表达式转化为二叉树的形式,其中每个节点都是一个运算符,叶子节点是操作数。
通过遍历二叉树,我们可以按照一定的顺序计算出表达式的值。
具体而言,我们可以使用二叉树的后序遍历(即左子树-右子树-根节点的遍历方式),来求解表达式。
在遍历过程中,如果节点为运算符,则计算其左右子树的值,并根据运算符进行相应的运算。
三、建立二叉树的过程接下来,我们将介绍如何根据表达式构建二叉树。
首先,我们需要定义二叉树的节点结构。
在本例中,节点包含一个运算符和两个指向左右子树的指针。
以下是一个示例的节点结构定义:struct Node {char operator;Node* left;Node* right;};接下来,我们可以使用递归的方式构建二叉树。
具体而言,我们可以从表达式的末尾开始查找运算符,这样我们可以将运算符作为根节点,并将其前面的表达式分割为左右两个子表达式。
例如,对于表达式"3 + 4 * 5",我们可以选择"*" 作为根节点,并将"4" 和"5" 作为其左右子节点。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验报告课程名称: 程序设计与数据结构 指导老师: ljq 成绩: 实验名称:基于二叉树结构的表达式求值算法 实验类型: 上机 同组学生姓名:一、实验目的和要求(必填)三、代码缺陷及修正记录五、讨论、心得二、实验内容和代码(必填) 四、实验结果与分析(必填)一、实验目的和要求1. 掌握编程工具的使用2. 掌握二叉树数据结构在计算机上的实现3. 掌握通过计算机编程解决问题的基本方法二、实验内容和代码1.实验内容:● 编程实现基于二叉树结构的表达式求值算法● 表达式包含加减乘除四则运算以及至少一层括弧运算● 首先将输入的原表达式转换成二叉树结构,然后采用二叉树的后序递归遍历方法求得表达式的值● 将所有实验内容合并到一个工程,增加交互操作和循环处理(持续)2.代码1.头文件expnbitree .h装订 线1 2 3 4 5 6 7 8 91011121314151617181920212223 #include<stdio.h>#include<string.h>#include<stdlib.h>#define EXP_LEN 100 //定义表达式的最大长度#define DATA_LEN 20 //定义每个操作数的最大长度typedef struct BiTNode{int dflag; //标志域,值为1,data[]存放操作运算符;值为0,data[]存放操作数char data[DATA_LEN + 1]; //数据域,存放:操作运算符或操作数struct BiTNode *lchild, *rchild; //分别指向结点的左、右子树}BiTNode, *BiTree; //定义二叉树结点及二叉树类型指针int CreateBiTree(BiTree &bt, char *p, int len);//创建二叉树,并用bt返回树的根地址,p为表达式的首地址,l为表达式的长度int Calculate(BiTree bt, double &rst);//计算表达式的值,bt为据表达式创建的二叉树,用rst返回表达式的值int PreOrderTraverse(BiTree bt);//先序遍历二叉树bt,输出先序遍历序列int InOrderTraverse(BiTree bt); //中序遍历二叉树bt,输出中序遍历序列int PostOrderTraverse(BiTree bt); //后序遍历二叉树bt,输出后序遍历序列int DestroyBiTree(BiTree &bt); //销毁二叉树//二叉树结构的表达式求解算法入口void expnbitree();2.源文件expntree.c1 2 3 4 5 6 7 8 910111213141516 #include<stdio.h>#include<string.h>#include<stdlib.h>#include"expnbitree.h"//ExpnBiTree实现子程序入口void expnbitree(){int n, len, i; //n标志量,值为0,退出程序;len存储表达式的长度;i一般变量char expn[EXP_LEN + 1]; //存放表达式double rst; //存放表达式计算结果BiTree bt = NULL; //声明一个二叉树gets_s(expn);do{1718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 i = 0;printf("请输入合法的表达式:\n");gets_s(expn);for (i = 0, len = 0; expn[i] != '\0'; i++) //去掉表达式中的空格,并计算表达式的长度if (expn[i] != ' ')expn[len++] = expn[i];expn[len] = '\0';printf("正在构建二叉树……\n");if (CreateBiTree(bt, expn, len))printf("二叉树构建成功!\n");else{ //销毁未成功建立的二叉树,释放动态申请的内存printf("二叉树构建失败!\n");printf("将销毁二叉树…………");if (DestroyBiTree(bt))printf("二叉树销毁成功!\n");else {printf("二叉树销毁失败!\n");exit(0);}continue;}printf("输出表达式的先序遍历序列……:\n");PreOrderTraverse(bt);printf("\n");printf("输出表达式的中序遍历序列……:\n");InOrderTraverse(bt);printf("\n");printf("输出表达式的后序遍历序列……:\n");PostOrderTraverse(bt);printf("\n");printf("计算表达式的值……:\n");if (Calculate(bt, rst))printf("%g\n", rst);elseprintf("计算表达式的值失败!\n");printf("即将销毁二叉树…………");if (DestroyBiTree(bt))printf("二叉树销毁成功!\n");else {printf("二叉树销毁失败!\n");exit(0);}printf("如果要继续计算下一个表达式,请输入1,否则,返回上一级:\n ");616263646566676869707172737475767778798081828384858687888990919293949596979899 100 101 102 103 104scanf_s("%d", &n);getchar();} while (n==1);}//创建二叉树int CreateBiTree(BiTree &bt, char *p, int len){int i = 0, lnum = 0, rpst1 = -1, rpst2 = -1, pn = 0;//lnum记录"("的未成对个数;//rpst1/rpst2记录表达式中优先级最低的("*"、"/")/("+"、"-")的位置;//pn记录操作数中"."的个数,以判断输入操作数是否合法if (len == 0)return 1;if (!(bt = (BiTree)malloc(sizeof(BiTNode)))) {printf("内存申请失败\n");return 0;}else{//初始化bt->lchild = bt->rchild = NULL;memset(bt->data, '\0', sizeof(bt->data));//memset是计算机中C/C++语言函数——memset(void*s,int ch,size_t n);//将s所指向的某一块内存中的后n个字节的内容全部设置为ch指定的ASCII值,//第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作,其返回值为s。
bt->dflag = 1;//默认bt为叶子节点(即,存放操作数)//合法性检查if (*p == '+' || *p == '*' || *p == '/' || *p == '.' || *p == ')') //表达式首不合法;{printf("表达式输入错误!\n");return 0;}if (!(*(p + len - 1) == ')' || *(p + len - 1) >= '0'&&*(p + len - 1) <= '9')) //不为右括弧或数字,则表达式尾不合法;{printf("表达式输入错误!\n");return 0;}if (len == 1) //此时只有表达式为数字,表达式才合法105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148if (*p<'0' || *p>'9') {printf("表达式输入错误!\n");return 0;}else {bt->data[0] = *p;return 1;}else if (len == 2) //此时只有表达式为正数或负数,表达式才合法if ((*p == '-' || *p >= '0'&&*p <= '9') && *(p + 1) >= '0'&&*(p + 1) <= '9') {bt->data[0] = *p; bt->data[1] = *(p + 1);return 1;}else {printf("表达式输入错误!\n");return 0;}//表达式合法,开始创建二叉树else{if (*p == '(')lnum++;for (i = 1; i < len; i++){//合法性检查if (*(p + i) == '.'){if (!(*(p + i - 1) >= '0'&&*(p + i - 1) <= '9')){printf("表达式输入错误!\n");return 0;}}else if (*(p + i) == '*' || *(p + i) == '/'){if (!(*(p + i - 1) >= '0'&&*(p + i - 1) <= '9' || *(p + i - 1) == ')')){printf("表达式输入错误!\n");return 0;}if (lnum == 0) rpst1 = i;}149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192else if (*(p + i) == '('){if (*(p + i - 1) == '+' || *(p + i - 1) == '-' || *(p + i - 1) == '*' || *(p+ i - 1) == '/' || *(p + i - 1) == '(')lnum++;else {printf("表达式输入错误!\n");return 0;}}else if (*(p + i) == ')'){if (*(p + i - 1) == ')' || *(p + i - 1) >= '0'&&*(p + i - 1) <= '9')lnum--;else {printf("表达式输入错误!\n");return 0;}if (lnum < 0) {printf("表达式输入错误!\n");return 0;}}else if (*(p + i) == '+' || *(p + i) == '-'){if (*(p + i) == '+'&&!(*(p + i - 1) >= '0'&&*(p + i - 1) <= '9' || *(p + i - 1) == ')')){printf("表达式输入错误!\n");return 0;}else if (*(p + i) == '-'&&!(*(p + i - 1) >= '0'&&*(p + i - 1) <= '9' ||*(p + i - 1) == ')' || *(p + i - 1) == '(')){printf("表达式输入错误!\n");return 0;}if (lnum == 0)rpst2 = i;}}if (lnum != 0) {printf("表达式输入错误!\n");return 0;194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 //"("、")"未能完全配对,表达式输入不合法if (rpst2 > -1)//+ -{bt->dflag = 0; //data[]存放操作数bt->data[0] = *(p + rpst2);if (CreateBiTree(bt->lchild, p, rpst2))if (CreateBiTree(bt->rchild, p + rpst2 + 1, len - rpst2 - 1))return 1;return 0;}if (rpst1 < 0)//此时表明表达式或者是一个数字,或是表达式整体被一对括弧括起来{if (*p == '(') //此时表达式整体被一对括弧括起来if (CreateBiTree(bt, p + 1, len - 2))return 1;else return 0;else{if (*(p + 1) != '(') //此时表达式一定是一个数字{for (i = 0; i < len; i++){if (*(p + i) == '.')pn++;if (pn > 1) {printf("表达式输入错误!\n");return 0;}bt->data[i] = *(p + i);}return 1;}else//此时表达式首一定是操作符"-",其余部分被一对括弧括起来{bt->dflag = 0; bt->data[0] = '-';if (CreateBiTree(bt->rchild, p + 2, len - 3))return 1;else return 0;}}238 239240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280else//此时表明表达式为几个因子想成或相除而组成的{bt->dflag = 0; bt->data[0] = *(p + rpst1);if (CreateBiTree(bt->lchild, p, rpst1))if (CreateBiTree(bt->rchild, p + rpst1 + 1, len - rpst1 - 1))return 1;return 0;}}}}//计算表达式int Calculate(BiTree bt, double &rst){double l = 0, r = 0;//l、r分别存放左右子树所代表的字表达式的值if (!bt) {rst = 0;return 1;}if (bt->dflag == 1) {rst = atof(bt->data);//atof(),是C语言标准库中的一个字符串处理函数,//功能是把字符串转换成浮点数,//所使用的头文件为<stdlib.h>。