表达式二叉树

合集下载

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

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

浙江大学城市学院实验报告课程名称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;}五、实验结果分析本实验设计并实现了基于二叉树的表达式求值程序。

二叉树表达式求值

二叉树表达式求值
{
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。

三、扩展上面的例子说明了如何将表达式转为二叉树,并计算表达式的值。

但实际中会有更复杂的表达式,如函数调用、变量引用等。

完全二叉树的总结点数公式

完全二叉树的总结点数公式

完全二叉树的总结点数公式完全二叉树是一种特殊的二叉树结构,它的每个节点都有两个子节点,除了最后一层的叶子节点外,其他层的节点都是满的。

在完全二叉树中,叶子节点只会出现在最后一层或者倒数第二层,并且最后一层的叶子节点都靠左排列。

在这篇文章中,我们将探讨完全二叉树的总结点数公式以及相关的性质。

完全二叉树的总结点数公式是一个重要的数学公式,它可以帮助我们计算完全二叉树中节点的数量。

这个公式的表达式如下:总结点数 = 2的h次方 - 1其中,h代表完全二叉树的高度。

这个公式的推导过程是基于完全二叉树的性质而得出的。

在完全二叉树中,每一层的节点数都是满的,除了最后一层。

因此,在计算总结点数时,我们只需要计算除了最后一层外的节点数量,然后再加上最后一层的节点数即可。

我们来看完全二叉树的第一层。

由于完全二叉树的定义,第一层只有一个节点,即根节点。

因此,第一层的节点数为1。

接下来,我们来看完全二叉树的第二层。

根据完全二叉树的定义,第二层的节点数等于第一层节点数的两倍,即2。

继续往下,我们可以得到第三层的节点数为4,第四层的节点数为8,以此类推。

可以观察到,每一层的节点数都是2的次方。

因此,我们可以用2的h次方来表示每一层的节点数。

接下来,我们需要计算除了最后一层之外的节点数。

在完全二叉树中,除了最后一层的节点数是满的,其他层的节点数都是满的。

如果完全二叉树的高度为h,那么除了最后一层之外的节点数可以用以下公式表示:除最后一层之外的节点数 = 2的(h-1)次方 - 1接下来,我们需要计算最后一层的节点数。

根据完全二叉树的定义,最后一层的节点数是小于或等于前面各层节点数的两倍。

因此,最后一层的节点数可以用以下公式表示:最后一层的节点数 = 2的(h-1)次方或者 2的h次方 - 2的(h-1)次方我们将除了最后一层之外的节点数和最后一层的节点数相加,即可得到完全二叉树的总结点数。

将上述公式代入,我们可以得到完全二叉树的总结点数公式:总结点数 = 2的(h-1)次方 - 1 + 2的h次方 - 2的(h-1)次方简化上述公式,我们可以得到:总结点数 = 2的h次方 - 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;右界初值为串长度。

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

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

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

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

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

二叉树 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,得到最终结果。

数据结构-二叉树类型的实现

数据结构-二叉树类型的实现

实验4 表达式二叉树类型的实现源代码及每步注解:文件expression.h/*头文件以及存储结构*/#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<string.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW 0typedef int Status;/*二叉树结点类型*/typedef enum{INT,CHAR}ElemTag;/*INT为整型数据num,CHAR为字符型数据c*/ typedef struct TElemType{ElemTag tag;/*{INT,CHAR}指示是整型还是字符型*/union{int num;/*tag=INT时,为整型*/char c;/*tag=CHAR时,为字符型*/};} TElemType;/*二叉树的二叉链表存储表示 */typedef struct BiTNode{TElemType data;struct BiTNode *lchild,*rchild; /* 左右孩子指针 */}BiTNode,*BiTree;typedef BiTree SElemType;/*栈SqStack的元素*/typedef char SElemType1; /*栈SqStack1的元素*//*栈的顺序存储表示 */#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */#define STACKINCREMENT 2 /* 存储空间分配增量 *//*两个顺序栈*/typedef struct SqStack{SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */SElemType *top; /* 栈顶指针 */int stacksize; /* 当前已分配的存储空间,以元素为单位 */}SqStack; /* 顺序栈 */typedef struct SqStack1{SElemType1 *base; /* 在栈构造之前和销毁之后,base的值为NULL */SElemType1 *top; /* 栈顶指针 */int stacksize; /* 当前已分配的存储空间,以元素为单位 */}SqStack1; /* 顺序栈 *//*顺序栈的基本操作*/Status InitStack(SqStack *S){ /* 构造一个空栈S */(*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));if(!(*S).base)exit(OVERFLOW); /* 存储分配失败 */(*S).top=(*S).base;(*S).stacksize=STACK_INIT_SIZE;return OK;}Status StackEmpty(SqStack S){ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */if(S.top==S.base) return TRUE;else return FALSE;}Status Push(SqStack *S,SElemType e){ /* 插入元素e为新的栈顶元素 */if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */{(*S).base=(SElemType*)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType));if(!(*S).base) exit(OVERFLOW); /* 存储分配失败 */(*S).top=(*S).base+(*S).stacksize;(*S).stacksize+=STACKINCREMENT;}*((*S).top)++=e;return OK;}Status Pop(SqStack *S,SElemType *e){ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */ if((*S).top==(*S).base) return ERROR;*e=*--(*S).top;return OK;}Status GetTop(SqStack S,SElemType *e)if(S.top>S.base){*e=*(S.top-1);return OK;}elsereturn ERROR;}/*顺序栈的基本操作*/Status InitStack1(SqStack1 *S){ /* 构造一个空栈S */(*S).base=(SElemType1 *)malloc(STACK_INIT_SIZE*sizeof(SElemType1));if(!(*S).base)exit(OVERFLOW); /* 存储分配失败 */(*S).top=(*S).base;(*S).stacksize=STACK_INIT_SIZE;return OK;}Status StackEmpty1(SqStack1 S){ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */if(S.top==S.base) return TRUE;else return FALSE;}Status Push1(SqStack1 *S,SElemType1 e){ /* 插入元素e为新的栈顶元素 */if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */{(*S).base=(SElemType1*)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType1));if(!(*S).base) exit(OVERFLOW); /* 存储分配失败 */(*S).top=(*S).base+(*S).stacksize;(*S).stacksize+=STACKINCREMENT;}*((*S).top)++=e;return OK;}Status Pop1(SqStack1 *S,SElemType1 *e){ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */ if((*S).top==(*S).base) return ERROR;*e=*--(*S).top;return OK;}Status GetTop1(SqStack1 S,SElemType1 *e)if(S.top>S.base){*e=*(S.top-1);return OK;}elsereturn ERROR;}文件expression.cpp#include"expression.h"/*全局变量*/int save_number[31];/*在按原表达式输入形式中,输入的常量保存到数组save_number中,常量最多为30个,0单元不用*/char Expr_String[30];/*存放表达式的字符串*//*以字符序列的形式输入语法正确的前缀表达式,保存到字符串string*//*参数flag=0表示输出的提示信息是"请输入正确的前缀表示式:"*//*flag=1表示输出的提示信息为"请以表达式的原书写形式输入正确表示式:"*/Status Input_Expr(char *string,int flag){if(flag==0)printf("\n请输入正确的前缀表示式:");else printf("\n请以表达式的原书写形式输入正确表示式:");flushall();/*清理缓冲区*/gets(string);/*从键盘输入一串字符串作为表达式*/if(strlen(string)==1)/*输入的表达式字符串长度为1*/if(string[0]=='+'||string[0]=='-'||string[0]=='*'||string[0]=='/'||string[0 ]=='^')/*输入的表达式只有一个运算符*/{ printf("\n表达式只有一个字符,为运算符,错误!");return ERROR;} elseif((string[0]>='0'&&string[0]<'9')||(string[0]>='a'&&string[0]<='z')||(string[0 ]>='A'&&string[0]<='Z'))/*输入的表达式只有一个数字或字符*/{ printf("\n表达式只有一个字符!");return OK;}else {printf("\n输入的字符不是运算符也不是变量常量,错误!");return ERROR;}return OK;}/*判断字符string[i],如果是'0'-'9'常量之间,二叉树结点存为整型;否则,存为字符型*/void judge_value(BiTree *E,char *string,int i){if(string[i]>='0'&&string[i]<='9')/*为常量*/{(*E)->data.tag=INT;(*E)->data.num=string[i]-48;}else if(string[i]>=1&&string[i]<=20)/*为常量,常量存于数组save_number中*/{(*E)->data.tag=INT;(*E)->data.num=save_number[string[i]];} else/*为变量*/{(*E)->data.tag=CHAR;(*E)->data.c=string[i];}}/*以正确的前缀表示式并构造表达式E*/Status ReadExpr(BiTree *E,char *exprstring){SqStack S;int i,len;/*len为表达式的长度*/BiTree p,q;(*E)=(BiTree)malloc(sizeof(BiTNode));/*申请二叉树的根结点的空间*/(*E)->lchild=NULL;(*E)->rchild=NULL;len=strlen(exprstring);/*len赋值为表达式的长度*/if(len==1)/*表达式长度为1时,二叉树只有根结点*/judge_value(E,exprstring,0);/*将exprstring[0]存入二叉树的结点中*/ else{judge_value(E,exprstring,0);/*将exprstring[0]存入二叉树的结点中*/InitStack(&S);/*初始化栈*/q=(*E);Push(&S,q);/*入栈*/Push(&S,q);/*入栈,根结点入栈两次是为判断先序输入的表达式是不是正确的表达式*/for(i=1;i<len&&!StackEmpty(S);i++){p=(BiTree)malloc(sizeof(BiTNode));judge_value(&p,exprstring,i);/*将exprstring[i]存入二叉树的结点中*/p->lchild=NULL;p->rchild=NULL;if(exprstring[i]=='+'||exprstring[i]=='-'||exprstring[i]=='*'||exprstring[i ]=='/'||exprstring[i]=='^'){/*为运算符,运算符入栈,左孩子不空,向左孩子走,否则,如果右孩子不空,向右孩子走*/if(!q->lchild) {q->lchild=p;Push(&S,p);q=p;}else {q->rchild=p;Push(&S,p);q=p;}}else/*不是运算符,运算符出栈*/{if(!q->lchild) {q->lchild=p;Pop(&S,&q);}else {q->rchild=p;Pop(&S,&q);}}}if(StackEmpty(S)&&i>=len) return OK;/*栈空且i>=len,说明输入的表达式是正确的*/else /*输入的表达式是错误的*/{printf("\n输入的表达式有误!");return ERROR;}}}/*如果两个字符是运算符,比较两个运算符的优先级,c1比c2优先,返回OK,否则返回ERROR*/Status Pri_Compare(char c1,char c2){if((c1=='^'||c1=='*'||c1=='-'||c1=='+'||c1=='/')&&(c2=='^'||c2=='*'||c2=='-'||c2=='+'||c2=='/')){/*c1和c2为运算符*/if(c1=='^')/*c1为指数运算符,则当c2不为'^'时,c1比c2优先*/{if(c2!='^') return OK;else return ERROR;}else if(c1=='*'||c1=='/')/*c1为乘法或除法运算符,则当c2为'+'或'-',c1比c2优先*/{if(c2=='^'||c2=='*'||c2=='/') return ERROR;else return OK;}else return ERROR;/*其余,c1不比c2优先*/}else return ERROR;/*c1和c2不是运算符*/}/*用带括弧的中缀表达式输入表达式*/void WriteExpr(BiTree E){if(E)/*树不为空*/{ /*先递归左子树*/if(E->lchild&&E->lchild->data.tag==CHAR)/*E的左孩子不为空,且左孩子为字符*/{if(Pri_Compare(E->data.c,E->lchild->data.c))/*E->data.c比E->lchild->data.c优先*/{printf("(");WriteExpr(E->lchild);printf(")");}/*带括弧输出左子树*/else WriteExpr(E->lchild);/*否则,不带括弧输出左子树*/}else WriteExpr(E->lchild);/*否则,输出左子树*//*访问输出根结点的值*/if(E->data.tag==INT){printf("%d",E->data.num);}else printf("%c",E->data.c);/*后递归右子树*/if(E->rchild&&E->rchild->data.tag==CHAR)/*E的右孩子不为空,且右孩子为字符*/{if(Pri_Compare(E->data.c,E->rchild->data.c))/*E->data.c比E->rchild->data.c优先*/{printf("(");WriteExpr(E->rchild);printf(")");}/*带括弧输出右子树*/else WriteExpr(E->rchild);/*否则,不带括弧输出右子树*/}else WriteExpr(E->rchild);/*否则,输出右子树*/}}/*实现对表达式中的所有变量V的赋值(V=c),参数flag为表示是否赋值过的标志*/ void Assign(BiTree *E,char V,int c,int *flag){if(*E){if((*E)->data.tag==CHAR&&(*E)->data.c==V)/*如果找到要赋值的变量,赋值*/{(*E)->data.tag=INT;(*E)->data.num=c;*flag=1;}Assign(&((*E)->lchild),V,c,flag);/*递归左子树*/Assign(&((*E)->rchild),V,c,flag);/*递归左子树*/}}/*指数运算函数,底数为x,指数为exp*/long power(int x,int exp){long result;int i;for(i=1,result=1;i<=exp;i++)result*=x;return result;}/*运算符运算求值,参数opr1,opr2为常量,opr为运算符,根据不同的运算符,实现不同的运算,返回运算结果*/long Operate(int opr1,char opr,int opr2){long result;switch(opr){case '+':/*加法*/result=opr1+opr2;return result;break;case '-':/*减法*/result=opr1-opr2;return result;break;case '*':/*乘法*/result=opr1*opr2;return result;break;case '/':/*除法,除法是在整型类型上的除法*/result=opr1/opr2;return result;break;case '^':/*指数运算*/result=power(opr1,opr2);return result;break;default:break;}}/*检查表达式是否还存在没有赋值的变量,以便求算数表达式的值*/Status Check(BiTree E){if(E&&E->data.tag==CHAR)/*树不为空*/{if(E->data.c!='*'&&E->data.c!='^'&&E->data.c!='-'&&E->data.c!='+'&&E->data. c!='/'){printf("\n表达式中仍存在变量没有赋值!没法求出表达式的值!");return ERROR;}/*存在变量,提示信息,后返回ERROR*/if(Check(E->lchild))/*递归左子树*/Check(E->rchild);/*递归右子树*/}}/*对算术表达式求值*/long Value(BiTree E){if(E)/*树不为空*/{if(!E->lchild&&!E->rchild&&E->data.tag==INT) return (E->data.num);/*结点的左孩子和右孩子为空,为叶子结点,返回结点的值*/return Operate(Value(E->lchild),E->data.c,Value(E->rchild));/*运算求值,后根遍历的次序对表达式求值,其中参数递归调用了Value()函数求左子树的值和右子树的值*/}}/*构造一个新的复合表达式*/void CompoundExpr(char P,BiTree *E1,BiTree E2){BiTree E;E=(BiTree)malloc(sizeof(BiTNode));/*申请一个结点存放运算符P*/E->data.tag=CHAR;E->data.c=P;/*申请到的结点值为P*/E->lchild=(*E1);/*结点的左孩子为E1*/E->rchild=E2;/*结点的右孩子为E2*/(*E1)=E;/*(*E1)为根结点*/printf("\n表达式E复合成功!其表达式变为:\n");WriteExpr(E);/*输出复合好的表达式*/}/*以表达式的原书写形式输入,表达式的原书写形式字符串string变为字符串pre_expr*//*后调用reversal_string()函数反转得到前缀表达式pre_expr*/Status Read_Inorder_Expr(char *string,char *pre_expr){int i,j,len,char_number=1;/*len表示字符串string的长度,char_number是记录数组save_number[]的个数*/int number;/*保存大于9的常量*/char c,c1;SqStack1 S;/*栈定义*/InitStack1(&S);/*初始栈*/Push1(&S,'#');/*先将字符'#'入栈,用来表示作为栈的最底一个元素*/len=strlen(string);/*len为字符串string的长度*/c=string[len-1];/*从字符串的最后一个字符开始向前扫描*/i=len-1;while(!StackEmpty1(S)&&i>=0)/*栈不为空且i大于等于0*/{if(c=='(')/*字符为'('*/{Pop1(&S,&c);/*出栈,赋值给c*/while(c!=')')/*假如c不为')',出栈*/{*pre_expr++=c;if(!StackEmpty1(S)&&GetTop1(S,&c1)&&c1!='#') Pop1(&S,&c);else {printf("\n输入的表达式有误!");return ERROR;}}}else if(c==')')/*字符为')',入栈*/{Push1(&S,c);}else if(c>='0'&&c<='9')/*字符为'0'-'9'之间,循环扫描string前一个字符,后确定常量的大小*/{number=c-48;/*number为第一个常量字符的ASCII码-48*/for(c1=string[i-1],j=1;(c1>='0'&&c1<='9')&&i>=0;j++,i--)/*循环扫描string前一个字符,求出常量后赋给number*/{number=(c1-48)*power(10,j)+number;/*number为扫描到的常量*/c1=string[i-2];}save_number[char_number]=number;/*将number存入到数组save_number中,下标为char_number*/*pre_expr++=char_number++;}else if((c>='a'&&c<='z')||(c>='A'&&c<='Z'))/*字符为'a'-'z'或'A'-'Z'之间的变量*/{/*string下一个字符不能为常量或变量,否则,出错*/if((string[i-1]>='0'&&string[i-1]<='9')||(string[i-1]>='A'&&string[i-1]<='Z ')||(string[i-1]>='a'&&string[i-1]<='z')){printf("\n输入的表达式有误!");return ERROR;}else *pre_expr++=c;}else if(c=='*'||c=='/')/*字符为运算符'*'或'/'*/{while(GetTop1(S,&c1)&&(c1=='^'))/*将c与栈顶的字符c1比较优先级*/{Pop1(&S,&c1);*pre_expr++=c1;}/*如果c1比c优先,出栈*/Push1(&S,c);/*入栈字符c*/}else if(c=='+'||c=='-')/*字符为运算符'+'或'-'*/{while(GetTop1(S,&c1)&&(c1=='^'||c1=='*'||c1=='/'))/*将c与栈顶的字符c1比较优先级*/{Pop1(&S,&c1);*pre_expr++=c1;}/*如果c1比c优先,出栈*/Push1(&S,c);/*入栈运算符c*/}else if(c=='^')/*字符为运算符'^'*/{Push1(&S,c);/*入栈运算符'^'*/}else {printf("\n输入的表达式有误!");return ERROR;}/*其他字符,错误,返回ERROR*/i--;/*下一个字符*/if(i>=0) c=string[i];/*i不小于0,c=string[i]循环下一个字符*/else /*否则,将清空栈*/while(!StackEmpty1(S)&&GetTop1(S,&c1)&&c1!='#'){Pop1(&S,&c);*pre_expr++=c;}}Pop1(&S,&c);/*将'#'出栈*/*pre_expr='\0';/*字符串结束符*/if(i<0&&StackEmpty1(S))return OK;else return ERROR;}/*将字符串exprstring反转过来*/void reversal_string(char *exprstring){int len,i,j;char temp;len=strlen(exprstring);/*len为exprstring的长度*/for(i=0,j=len-1;i<j;i++,j--)/*字符串前后两个字符对换*/{temp=exprstring[i];exprstring[i]=exprstring[j];exprstring[j]=temp;}}/*常数合并操作函数,合并表达式E中所有常数运算*/void MergeConst(BiTree *E){long result;if((*E)->lchild&&(*E)->rchild)/*左右孩子不为空*/{if((*E)->lchild->data.tag==INT&&(*E)->rchild->data.tag==INT)/*假如左右孩子为常量,合并*/{result=Operate((*E)->lchild->data.num,(*E)->data.c,(*E)->rchild->data.num); /*常数合并运算,调用Operate()函数求值*/(*E)->data.tag=INT;(*E)->data.num=result;/*修改之前的运算符为常量*/free((*E)->lchild);/*释放左孩子*/free((*E)->rchild);/*释放右孩子*/(*E)->lchild=(*E)->rchild=NULL;/*左右孩子置空*/}else{MergeConst(&((*E)->lchild));/*递归左孩子*/MergeConst(&((*E)->rchild));/*递归右孩子*/}}}/*主菜单*/char menu(){char choice;printf("\n\t****************************************");printf("\n\t K网络工程121班");printf("\n\t 学号:240121525 姓名:王云峰");printf("\n\t****************************************");printf("\n\t***********表达式类型的实现*************");printf("\n\t 1 >>>输入正确的前缀表达式");printf("\n\t 2 >>>带括弧的中缀表示式输出");printf("\n\t 3 >>>对变量进行赋值");printf("\n\t 4 >>>对算数表达式求值");printf("\n\t 5 >>>构造一个新的复合表达式");printf("\n\t 6 >>>以表达式的原书写形式输入");printf("\n\t 7 >>>合并表达式中所有常数运算");printf("\n\t 0 >>>退出");printf("\n\t****************************************");printf("\n\t请输入你的选择>>>>>");choice=getche();return choice;}/*主函数*/void main(){BiTree E,E1;/*两个表达式E和E1*/int flag=0;/*表达式E构造标志,为0表示未构造,为1表示已构造*/long result;/*保存算数表达式运算结果*/char V,P;int c;char string[30];while(1){ system("cls");switch(menu()){case '1':/*1 >>>输入正确的前缀表达式*/printf("\n\t*************************输入提示信息************************");printf("\n\t输入正确的前缀表达式的要求:");printf("\n\t\t【变量】 a-z或A-Z");printf("\n\t\t【常量】 0-9,不能超过9");printf("\n\t\t【运算符】 +,-,*,/,^(乘幂)");printf("\n\t请输入正确的前缀表达式,后按回车键存入缓冲区,否则可能会出错!");printf("\n\t*************************************************************") ;if(Input_Expr(Expr_String,0))if(ReadExpr(&E,Expr_String)){flag=1;printf("\n表达式构造成功!\n输入的带括弧的中缀表达式:");WriteExpr(E);}getch();break;case '2':/*2 >>>带括弧的中缀表示式输出*/printf("\n\t********************输出说明信息***********************************");printf("\n\t输出带括弧的中缀表达式:");printf("\n\t【1】如果表达式已经构造成功的,输出表达式;");printf("\n\t【2】如果表达式还未构造成功的,请返回主菜单选择构造表达式;");printf("\n\t【注】其中要注意的是,可能有一些表达式构造时没有办法判断为有误,");printf("\n\t 如果输出不是你想得到的,说明你之前输入的表达式有误,请重新构造!");printf("\n\t*************************************************************** *****");if(flag==1) {printf("\n带括弧的中缀表达式为:");WriteExpr(E);}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '3':/*3 >>>对变量进行赋值*/printf("\n\t********************赋值操作说明信息***********************************");printf("\n\t赋值操作:实现对表达式中的某一个变量V的赋值,即使V=C,C为一整数");printf("\n\t 【1】根据输出的表达式,输入要赋值的变量V,只能输入一个字符,否则出错");printf("\n\t 【2】输入要将变量V赋值为的整数C,只能是整数,否则出错");printf("\n\t 【注】如果表达式未构造,请回到主菜单选择构造表达式");printf("\n\t*************************************************************** ********");if(flag==1){int Assign_flag=0;printf("\n表达式E为:");WriteExpr(E);flushall();/*清理缓冲区*/printf("\n请输入要赋值的值:");V=getchar();printf("请输入要将赋值为:");scanf("%d",&c);Assign(&E,V,c,&Assign_flag);if(Assign_flag) {printf("\n赋值成功!\n赋值后的表达式为:");WriteExpr(E);}else printf("\n表达式里没有%c这个变量!",V);}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '4':/*4 >>>对算数表达式求值*/printf("\n\t********************算数表达式求值说明信息************************");printf("\n\t 【注】如果表达式还有变量未赋值,即表达式不是算数表达式");printf("\n\t 不能求出表达式的值,请回到主菜单选择赋值操作,后再求值");printf("\n\t*************************************************************** ***");if(flag==1){printf("\n算数表达式:");WriteExpr(E);if(Check(E)){result=Value(E);printf("\n求算数表达式的值:\t");WriteExpr(E);printf("=%ld",result);}}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '5':/*5 >>>构造一个新的复合表达式*/printf("\n\t*****************构造新的复合表达式说明信息***************************");printf("\n\t 【1】构造一个新的表达式E1,采用表达式的原书写形式输入");printf("\n\t 【2】构造表达式E1成功后,输入要复合表达式E 和E1的操作运算符(+,-,*,/,^)");printf("\n\t 【注】如表达式E未构造,不能复合表达式;如构造表达式E1错误,复合失败");printf("\n\t*************************************************************** ********");if(flag==1){printf("\n表达式E1为:");WriteExpr(E);printf("\n请构造新的表达式E2:");flushall();/*清理缓冲区*/if(Input_Expr(string,1)){if(Read_Inorder_Expr(string,Expr_String)){reversal_string(Expr_String);if(ReadExpr(&E1,Expr_String)){flag=1;printf("\n表达式E1构造成功!");WriteExpr(E1);printf("\n请输入要构造新的复合表达式的操作运算符>>>");P=getchar();while(P!='*'&&P!='/'&&P!='+'&&P!='-'&&P!='^'){flushall();/*清理缓冲区*/printf("\n输入的操作运算符有误!请重新输入>>>");P=getchar();}CompoundExpr(P,&E,E1);}else printf("\n复合新的表达式失败!请按任意键返回主菜单!");}}}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '6':/*6 >>>以表达式的原书写形式输入*/printf("\n\t*************以表达式的原书写形式输入说明信息************************");printf("\n\t输入正确的原书写形式表达式");printf("\n\t 【变量】 a-z或A-Z");printf("\n\t 【常量】大于等于0的正整数");printf("\n\t 【运算符】 +,-,*,/,^(乘幂)");printf("\n\t 【括弧】左括弧 ( ,右括弧 ) ");printf("\n\t 【注】表示式中常量最多只能是30个,超过30个,出错!");printf("\n\t按原书写形式输入中,请按照正确的方式输入,否则可能会出错!");printf("\n\t*************************************************************** *******");if(Input_Expr(string,1))if(Read_Inorder_Expr(string,Expr_String)){reversal_string(Expr_String);if(ReadExpr(&E,Expr_String)){flag=1;printf("\n表达式构造成功!\n输入的带括弧的中缀表达式:");WriteExpr(E);}}getch();break;case '7':/*7 >>>合并表达式中所有常数运算*/printf("\n***************合并表达式中的所有常数运算*******************************");printf("\n 【注】合并表达式中的所有常数运算并不能一次性将常数都合并!");printf("\n例如:表达式'1+2*(3+3*4+9/3)'的常数合并,选择7进行合并,结果变为\n'1+2*(3+12+3)',");printf("根据优先级先后合并的,如果要合并到最后,需多次选择7\n进行合并,又合并一次'1+2*(15+3)',");printf("再次合并'1+2*18',再次合并'1+36',\n再次合并'37',后无法合并!");printf("\n***************************************************************** *******");if(flag==1){printf("\n原表达式为:");WriteExpr(E);MergeConst(&E);printf("\n合并表达式中所有的常数运算后的表达式:");WriteExpr(E);}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '0':/*0 >>>退出*/printf("\n请按任意键退出!");getch();exit(0);default :printf("\n输入有误!请按任意键回到主菜单重新选择!");getch();break;}}}。

利用二叉树求表达式的值

利用二叉树求表达式的值

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

节点与节点之间存在关联关系,这种关联关系的基本长度是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。

构造表达式二叉树

构造表达式二叉树

构造表达式二叉树构造表达式二叉树,需要先确定二叉树的构造规则,然后将表达式按照规则转换为对应的二叉树结构。

下面是一个简单的例子,演示如何构造一个表达式的二叉树:假设我们有一个简单的四则运算表达式:3 + 4 2 - 1 / 2。

根据二叉树的构造规则,我们可以将这个表达式转换为如下的二叉树结构:```+/ \3/ \4 2/ \- 1/ \/ 2```这个二叉树表示的表达式是:3 + (4 2) - (1 / 2)。

其中,根节点表示运算符"+",左子树表示3,右子树是一个二叉树,根节点表示运算符"",左子树表示4,右子树表示2。

在右子树的下面是一个三叉树,根节点表示运算符"-",左子树是空,中子树表示1,右子树是一个二叉树,根节点表示运算符"/",左子树是空,右子树表示2。

在构造这个二叉树时,需要注意以下几点:1. 先处理运算符和操作数。

在表达式中,运算符和操作数之间有一个空格。

在构造二叉树时,我们需要保留这个空格,将其视为两个节点的分隔符。

2. 根据运算符的优先级和结合性,确定子树的构造顺序。

在本例中,""的优先级高于"+",所以先构造""的子树。

同时,""是左结合的,所以先构造左子树。

3. 对于复杂的表达式,需要使用括号来明确运算顺序。

在本例中,"1 / 2"被括起来,表示先进行除法运算。

在构造二叉树时,需要将括号视为一个节点,并将其作为父节点包含其它的子节点。

二叉树的表达式求值

二叉树的表达式求值

⼆叉树的表达式求值问题描述: 输⼊⼀个表达式(表达式中的数均为⼩于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;}} 可能我写的过于复杂,有同学做的⽐较好 。

表达式二叉树的构建

表达式二叉树的构建

表达式二叉树的构建
在计算机科学中,表达式二叉树是一种数据结构,用于表示数学表达式。

表达式二叉树通常使用二叉树的数据结构来表示数学表达式的运算符和操作数。

下面是一个简单的示例,说明如何构建一个表达式二叉树。

假设我们有一个数学表达式:(a + b) * (c - d) / e。

我们可以将这个表达式转换为一个二叉树,其根节点表示整个表达式,左子树表示第一个括号内的表达式,右子树表示第二个括号内的表达式。

下面是构建这个表达式二叉树的步骤:
1. 首先,将表达式转换为后缀表达式(也叫逆波兰表示法)。

后缀表达式是一种不需要括号的表示法,运算符位于操作数之后。

对于上面的例子,后缀表达式为:abc+d-e*。

2. 根据后缀表达式构建二叉树。

根节点是一个新的节点,它的左子树表示第一个操作数和第一个运算符(a、b、+),右子树表示第二个操作数和第二个运算符(c、d、-)。

根节点的父节点表示整个表达式。

3. 继续按照后缀表达式的顺序构建子树,直到所有的操作数和运算符都被处理。

通过这个过程,我们可以构建一个表示给定数学表达式
的二叉树。

然后,可以使用这个二叉树来进行表达式的求值和化简等操作。

表达式转表达式二叉树

表达式转表达式二叉树

表达式转表达式⼆叉树表达式树⼆叉树是表达式处理的常⽤⼯具,例如,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 }前缀式、中缀式、后缀式前缀表达式和后缀表达式分别对应表达式树前序和后序遍历的结果,如果不考虑括号,中缀表达式对应表达式树中序遍历的结果。

二叉树求解表达式代码编写 -回复

二叉树求解表达式代码编写 -回复

二叉树求解表达式代码编写-回复如何使用二叉树求解表达式。

引言:在计算机科学中,表达式求解是一项非常基本且重要的任务。

通过将表达式转换为计算机能够理解和处理的形式,我们可以利用计算机来自动求解各种表达式。

在本文中,我们将介绍如何使用二叉树来求解表达式,详细解释每个步骤,并提供相关的代码示例。

一、表达式的构成和表示方法在开始之前,让我们先了解一下表达式的构成和常见的表示方法。

表达式由运算符和操作数组成,运算符用于指定操作数之间的运算关系。

常见的运算符包括加法、减法、乘法、除法等。

表达式通常以中缀表示法展示,即运算符出现在操作数之间。

例如,表达式"3 + 4" 中的运算符是"+",操作数是3 和4。

二、二叉树表示方法为了方便表达式的求解,我们可以将表达式转化为二叉树的形式,其中每个节点都是一个运算符,叶子节点是操作数。

通过遍历二叉树,我们可以按照一定的顺序计算出表达式的值。

具体而言,我们可以使用二叉树的后序遍历(即左子树-右子树-根节点的遍历方式),来求解表达式。

在遍历过程中,如果节点为运算符,则计算其左右子树的值,并根据运算符进行相应的运算。

三、建立二叉树的过程接下来,我们将介绍如何根据表达式构建二叉树。

首先,我们需要定义二叉树的节点结构。

在本例中,节点包含一个运算符和两个指向左右子树的指针。

以下是一个示例的节点结构定义:struct Node {char operator;Node* left;Node* right;};接下来,我们可以使用递归的方式构建二叉树。

具体而言,我们可以从表达式的末尾开始查找运算符,这样我们可以将运算符作为根节点,并将其前面的表达式分割为左右两个子表达式。

例如,对于表达式"3 + 4 * 5",我们可以选择"*" 作为根节点,并将"4" 和"5" 作为其左右子节点。

中缀表达式转二叉树

中缀表达式转二叉树

中缀表达式转二叉树
从最后被计算的运算符开始,分成三部分
运算符为树根,运算符左边为左子树,右边为右子树
a +
b ∗(
c −
d ) −
e / f
1、从左到右遍历表达式,找到最后计算的字符-
2、分成3部分a+b*(c-d),-,e/f,分别为左子树,根,右子树
3、再继续把每个拆分成三部分,左侧a ,+,b*(c-d);右侧e,/,f
4、继续就这样拆分成三部分,最终得到一棵完整的二叉树
中缀表达式转二叉树就完成了
建完这棵树之后求前缀和后缀表达式就很简单了,分别求它前序遍历和后序遍历
这棵树转中缀表达式只要求中序遍历(注意求的时候如果当前子树优先级比它的父亲低,则在子树外面套一个括号,具体操作自己根据上面那棵树自己模拟)
当用前缀或后缀表达式转二叉树时则更简单,因为根是运算符,接着用普通的前缀后缀表达式转二叉树的方法就可以了。

中缀表达式生成二叉树

中缀表达式生成二叉树

中缀表达式⽣成⼆叉树中缀表达式⽣成⼆叉树,⼤概应该有递规,迭代,和编译原理中的⾃顶向下的预测分析法等。

递规,迭代的思路每次读出⼀个数字,⼀个运算符,⽐较当前运算符和之前符号的优先级,进⾏相关的操作。

⾃顶向下的预测分析法,做了下,实在忘记的差不多了,先占个位。

以后完成。

tree.c#include "head.h"struct Node * CreateNodesetV(int number,char opr,int type){struct nodeData db;db.numberValue=number;db.operatorValue=opr;db.symbolType=type;struct Node * myNode=malloc(sizeof(struct Node));CreateNode(db,myNode);return myNode;};void CreateNode(struct nodeData nd,struct Node * myN){myN->NData.numberValue=nd.numberValue;myN->NData.operatorValue=nd.operatorValue;myN->NData.symbolType=nd.symbolType;myN->lchilden='\0';myN->rchilden='\0';};char insertNode(struct Node * myNode,struct Node * father,char lr){char result='Y';if(lr=='L'){if(father->lchilden=='\0'){father->lchilden=myNode;}else{result='N';}}else{if(father->rchilden=='\0'){father->rchilden=myNode;}else{result='N';}}return result;}//原来树的遍历也就是递归.我去,我说⾃⼰怎么⽼是不得要领.根源在于没想明⽩递归函数.void visitTree(struct Node * Root){if(Root->lchilden!='\0'){visitTree(Root->lchilden);}else{//终⽌递归的确定事件,是⽆事件.}if(Root->NData.symbolType==1){printf("%d",Root->NData.numberValue);}else{printf("%c",Root->NData.operatorValue);}if(Root->rchilden!='\0'){visitTree(Root->rchilden);}else{//终⽌递归的确定事件,是⽆事件.}}//所以如果⽤递归来做运算必须是后序遍历,要等左右树都有结果了,才⽤符号。

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

第4次上机实习报告2 数据结构与算法实习报告诚信保证:我保证没有抄袭他人作业!问题部分1.1 问题描述【1】对于任意给出的前缀表达式(不带括号)、中缀表达式(可以带括号)或后缀表达式(不带括号),能够在计算机内部构造出一棵表达式二叉树,并且图示出来(图形的形式)。

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

(2)输入输出要求:请输入表达式类型;请输入表达式类型,前缀表达式输入-1,中缀表达式输入0,后缀表达式输入1.请输入字符串表达式:树形二叉树(图形显示)中缀表达式为:前缀表达式为:后缀表达式为:1.2 问题分析一、前缀、中缀、后缀表达式->二叉树表达式数据结构实习报告前缀表达式->二叉树表达式:从后往前扫描(a)碰到操作数则把其值赋给相应的新申请的二叉树结点,地址压栈;(b)碰到操作符则把其值赋给相应的新申请的二叉树,若栈非空,从栈中弹出一个地址,则栈顶指针所指结点设置成当前结点左孩子,若栈非空,再从栈中弹出一个地址,则栈顶指针所指结点设置成当前结点右孩子,操作完毕后把当前节点压栈,最后一个地址即为二叉树的根结点地址。

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

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

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

二叉树表达式->中缀表达式:对二叉树表达式进行中序遍历,如果当前节点的左子树是运算符,且运算符优先级低于当前运算符,那么左边的表达式要先计算,需要加括号,否则直接输出左子树;如果当前节点的右子树是运算符,且运算符优先级不高于当前运算符,那么右边的表达式要先计算,需要加括号,狗则直接输出右子树。

4 数据结构与算法实习报告二叉树表达式->后缀表达式:对二叉树表达式进行后序遍历。

2 实现部分2.1 实现方法分析节点类TNode:包含操作符oper、左孩子left、右孩子right,isOper()判断是否为操作符,getOperOrder()返回运算符op所对应的优先级,freeTree()程序结束销毁二叉树,postOrder()先序遍历,preOrder()后序遍历,inOrder ()中序遍历并输出不带冗余括号的中缀表达式,post2tree()后缀表达式生成二叉树,pre2tree()前缀表达式生成二叉树,in2tree()中后缀表达式生成二叉树,count()求树的层数用于打印树做辅助,paint()打印2.2 测试效果分析------------function start-----------------请输入表达式类型,前缀表达式输入-1,中缀表达式输入0,后缀表达式输入1.请输入字符串表达式:(a+b)*c-d数据结构实习报告 -* d+ ca b中缀表达式为:(a+b)*c-d前缀表达式为:-*+abcd后缀表达式为:ab+c*d-----------function end-----------Press any key to continue------------function start-----------------请输入表达式类型,前缀表达式输入-1,中缀表达式输入0,后缀表达式输入1.-1请输入字符串表达式:-*+abcd-* d6 数据结构与算法实习报告+ ca b中缀表达式为:(a+b)*c-d前缀表达式为:-*+abcd后缀表达式为:ab+c*d-----------function end-----------Press any key to continue------------function start-----------------请输入表达式类型,前缀表达式输入-1,中缀表达式输入0,后缀表达式输入1.1请输入字符串表达式:ab+c*d--* d+ c数据结构实习报告a b中缀表达式为:(a+b)*c-d前缀表达式为:-*+abcd后缀表达式为:ab+c*d-----------function end-----------Press any key to continue3 报告总结在建树的时候要特别注意用到栈来实现节点顺序的改变,从而实现小树建造大树的过程。

前序建树和中序建树的过程的差别也特别值得注意。

用树的图形输出树实在是不会写,借鉴的别人的程序。

程序:#include<iostream>#include<stack>#include<queue>#include<string>#include<math.h>using namespace std;class TNode//节点类{ public:char oper;//数据域,为简便起见,操作数用单个字符代替TNode *left;TNode *right;8 数据结构与算法实习报告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);}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->left);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)){10 数据结构与算法实习报告cout<<"(";inOrder(p->right);cout<<")";}elseinOrder(p->right);}}}void post2tree(TNode *&p,string str)//后缀表达式生成二叉树{ //(a)碰到操作数则把其值赋给相应的新申请的二叉树结点,若栈为空则地址压栈,//(b)碰到操作符则把其值赋给相应的新申请的二叉树结点,取栈顶元素,//若当前元素的左孩子为空则设为其左孩子,//左孩子为满则设为其右孩子,开始那个元素地址为根结点地址,开始时用变量root保存。

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 pre2tree(TNode *&p, string str)//前缀表达式生成二叉树{//碰到操作数则把其值赋给相应的新申请的二叉树结点,地址压栈;//碰到操作符则把其值赋给相应的新申请的二叉树,并从栈中弹出两个地址,//分别作为其左指针和右指针,然后再把其地址压栈,最后一个地址即为二叉树的根结点地址。

相关文档
最新文档