运用表达式树求解表达式的值–洛谷AC

  • Post author:
  • Post category:其他




题目背景

表达式的计算曾用算符优先法,本题用表达式树来计算表达式的值。



题目描述

表达式树是一种特殊类型的树,其叶结点是操作数(operand),而其它结点为操作符(operator):

(1)由于操作符一般都是双目的,通常情况下该树是一棵二叉树;

(2)对于单目操作符(如++),其只有一个子结点。

如表达式:a+b*(c-d)-e/f的后缀表示式为abcd-+ef/-

对应的表达式树为:(见PPT)

题目要求从标准输入中读入一个整数算术运算表达式,计算表达式结果,并输出。

说明:

1、表达式运算符只有+、-、、/,表达式末尾的=字符表示表达式输入结束,表达式中可以出现空格;

2、表达式中会出现圆括号,括号可能嵌套,不会出现错误的表达式;

3、出现除号/时,以整数相除进行运算,结果仍为整数,例如:5/3结果应为1。

4、要求采用表达式树来实现表达式计算。



输入格式

从键盘输入一个以=结尾的整数算术运算表达式。操作符和操作数之间可以有空格分隔。



输出格式

首先在屏幕上输出表达式树根、左子节点及右子节点上的运算符或操作数,中间由一个空格分隔,最后有一个回车(如果无某节点,则该项不输出)。然后输出表达式计算结果。



输入输出样例

在这里插入图片描述



说明/提示

按照运算符及括号优先级依次计算表达式的值。在生成的表达树中,*是根节点的运算符,/ 是根节点的左子节点上运算符,/是根节点的右子节点上运算符。

#include

#include<stdio.h>

#include <string.h>

#include

using namespace std;

/

—————————二叉树的链式存储———————–

/

typedef struct BiTNode

{


char data; //结点数据域(符号)

string combine_data; //结点数据域(数值,可大于9)

BiTNode *lchild,

rchild; //左右孩子指针

}

BiTree;

/

——————————链式堆栈—————————

/

typedef struct StackNode

{


BiTree data_tree; //存储的是二叉树

char data_op; //存储的是符号

StackNode *next;

}*LinkStack;

//栈的初始化

int InitStack(LinkStack &S)

{


S = NULL;

return 1;

}

//二叉树入栈

int Push_tree(LinkStack &S, BiTree e)

{


LinkStack p = new StackNode;

p->data_tree = e;

p->next = S;

S = p;

return 1;

}

//字符(运算符号)入栈

int Push_op(LinkStack &S, char e)

{


LinkStack p = new StackNode;

p->data_op = e;

p->next = S;

S = p;

return 1;

}

//二叉树出栈

int Pop_tree(LinkStack &S, BiTree &T1)

{


if (S == NULL) return 0;

LinkStack p = S;

T1 = p->data_tree;

S = S->next;

delete p;

return 1;

}

//字符(运算符号)出栈

int Pop_op(LinkStack &S, char &ch)

{


if (S == NULL) return 0;

LinkStack p = S;

ch = p->data_op;

S = S->next;

delete p;

return 1;

}

//取栈顶元素

char GetTop_op(LinkStack S)

{


if (S != NULL) return S->data_op;

else return ’ ‘;

}

BiTree GetTop_tree(LinkStack S)

{


if (S != NULL) return S->data_tree;

else return NULL;

}

/

——————————表达式树的创建算法——————————

/

//创建以T为根结点的二叉树(存储符号)

void CreateExpTree(BiTree &T, BiTree a, BiTree b, char theta)//a是左孩子,b是右孩子,theta是数据域

{


BiTree L = new BiTNode;

L->data = theta;

L->lchild = a;

L->rchild = b;

T = L;

}

//创建以T为根结点的二叉树(存储数值,可大于9)

//a是左孩子,b是右孩子,theta是数据域

void CreateExpTree_str(BiTree &T, BiTree a, BiTree b, string theta)

{


BiTree L = new BiTNode;

L->combine_data = theta;

L->lchild = a;

L->rchild = b;

T = L;

}

//比较运算符的优先级

//top是栈顶元素,ch是需要比较的元素

char Precede(char top, char ch)

{


if (ch == ‘)’&&top == ‘(’) return ‘=’;

else if (ch == ‘)’) return ‘>’;

if (top == ’ ’ || top == ‘(’ || ch == ‘(’) return ‘<’;

if (ch == ‘=’) return ‘>’;

if (top == ‘+’ || top == ‘-’) {


if (ch == ‘+’ || ch == ‘-’) return ‘>’;

else if (ch == ‘/’ || ch == ‘

’) return ‘<’;

}

else if (top == ‘

’ || top == ‘/’) return ‘>’;

}

//创建表达式树

//expt栈(根结点),optr栈(运算符)

void InitExpTree(char ep[], LinkStack &expt, LinkStack &optr)

{


int n = strlen(ep);

int i = 0;

BiTree T = NULL; //树根

BiTree T1 = NULL; //左子树

BiTree T2 = NULL; //右子树

char ch = ’ ‘; //弹出的符号

string combine_str = “”; //存储数值,可大于9

while (i != n)

{


if (ep[i] >= ‘0’ && ep[i] <= ‘9’) { //数值(二叉树),进入expt栈中

combine_str += ep[i];

if (ep[i + 1] >= ‘0’ && ep[i + 1] <= ‘9’) { //下一位仍是数字,需连接

i++;

continue;

}

CreateExpTree_str(T, NULL, NULL, combine_str);

combine_str = “”; //建完数值的二叉树后string要置空

Push_tree(expt, T);

i++;

}

else {


switch (Precede(GetTop_op(optr),ep[i])) //比较优先级

{


case ‘<’:

Push_op(optr, ep[i]);

i++;

break;

case ‘>’:

Pop_op(optr, ch); //弹出上一个字符

Pop_tree(expt, T1); //弹出上两个数值(二叉树)

Pop_tree(expt, T2);

CreateExpTree(T, T2, T1, ch); //以data_tree为根,连接T1和T2两颗子树

Push_tree(expt, T); //最后把T放进expt栈中

break;

case ‘=’:

Pop_op(optr, ch);

i++;

break;

default:

break;

}

}

}

}

//表达式树 打印前三个op or num

void showOp(BiTree T)

{


if (T)

{


cout << T->data;

if (T->lchild != NULL) cout << ” ” << T->lchild->data;

if (T->rchild != NULL) cout << ” ” << T->rchild->data;

cout << endl;

}

/

if(T){


cout << T->data << ” “;

if (T->lchild->lchild == NULL)

cout << T->lchild->combine_data << ” “;

else

cout << T->lchild->data << ” “;

if (T->rchild->lchild == NULL)

cout << T->rchild->combine_data << endl;

else

cout << T->rchild->data << endl;

}

/

}

/

—————————–表达式树的求值——————————-

/

//直接初始化一个数组好使,用getchar现输入有一点问题

double GetValue(char data, double lvalue, double rvalue)

{


switch (data)

{


case ‘+’:

return lvalue + rvalue;

break;

case ‘-’:

return lvalue – rvalue;

break;

case ‘*’:

return lvalue * rvalue;

break;

case ‘/’:

return lvalue / rvalue;

break;

default:

break;

}

}

//把string字符转换成数值

double change(string str)

{


int n = str.length(), m = str.length();

double sum = 0;

for (int i = 0; i < n; i++)

{


sum += (str[i] – ‘0’) * pow(10, m – 1);

m–;

}

return sum;

}

//遍历表达式树求表达式的值

int EvaluateExpTree(BiTree T)

{


int lvalue =0, rvalue = 0; //存放叶子结点的数据域初始为0

if (T->lchild == NULL&&T->rchild == NULL)

return change(T->combine_data); //return T->data – ‘0’;

else {


lvalue = EvaluateExpTree(T->lchild); //相当于后序遍历二叉树

rvalue = EvaluateExpTree(T->rchild);

return GetValue(T->data, lvalue, rvalue);

}

}

int main()

{


LinkStack expt;

InitStack(expt); //初始化expt栈(根结点)

LinkStack optr;

InitStack(optr); //初始化optr栈(运算符)

char ep[100];

char temp;

int i=0;

for(i=0;temp!=’=’;i++){


cin>>temp;

ep[i]=temp;

}

ep[i]=’\0’;

/

char ep[100];

char temp;

int i=0;

while((temp=getchar())!=’=’) ep[i++]=temp;

ep[i]=’\0’;

/

//char ep[] = “24/(1+2+36/6/2-2)

(12/2/2)=”; //”24/(1+2+36/6/2-2)

(12/2/2)=”

InitExpTree(ep, expt, optr); //构建表达式树

BiTree T = NULL;

Pop_tree(expt, T); //获取最后建好的二叉树

showOp(T);

cout << EvaluateExpTree(T) << endl; //表达式树求值结果

return 0;

}“`cpp




版权声明:本文为weixin_45800653原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。