四则运算表达式求值.docx

上传人:b****8 文档编号:23662481 上传时间:2023-05-19 格式:DOCX 页数:21 大小:169.18KB
下载 相关 举报
四则运算表达式求值.docx_第1页
第1页 / 共21页
四则运算表达式求值.docx_第2页
第2页 / 共21页
四则运算表达式求值.docx_第3页
第3页 / 共21页
四则运算表达式求值.docx_第4页
第4页 / 共21页
四则运算表达式求值.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

四则运算表达式求值.docx

《四则运算表达式求值.docx》由会员分享,可在线阅读,更多相关《四则运算表达式求值.docx(21页珍藏版)》请在冰豆网上搜索。

四则运算表达式求值.docx

四则运算表达式求值

HUNANUNIVERSITY

背景

在工资管理软件中,不可避免的要用到公式的定义及求值等问题。

对于数学表达式的计算,虽然可以直接对表达式进行扫描并按照优先级逐步计算,但也可以将中缀表达式转换为逆波兰表达式,这样更容易处理。

问题描述

四则运算表达式求值,将四则运算表达式用中缀表达式,然后转换为后缀表达式,并计算结果。

一.需求分析

(1)本程序利用二叉树后序遍历来实现表达式的转换,同时可以使用栈来求解后缀表达式的值。

(2)输入输出的格式:

输入:

在字符界面上输入一个中缀表达式,回车表示结束。

输出:

如果该中缀表达式正确,那么在字符界面上输出其后缀表达式和计算结果,其中后缀表达式中两相邻操作数之间利用空格隔开;如果不正确,在字符界面上输出表达式错误提示。

(3)测试用例:

输入:

21+23*(12-6)+9

输出:

2123126-*+9+

resultis168

二.概要设计

(1)抽象数据类型:

由于四则运算表达式中运算符可能有多个后继,而运算的对象无后继,可以采用二叉树来实现把中缀表达式转换为后缀表达式。

数据对象:

四则运算符及整数

数据关系:

运算符有多个后继,二运算对象的值无后继

基本操作:

后序遍历,二叉树的构建和摧毁,插入,删除

经过二叉树的后序遍历后的表达式惊醒运算是满足后进先出的原则,采用栈来实现四则运算表达式的求值。

数据对象:

运算符(字符)及整数

数据关系:

后进先出

基本操作:

入栈,出栈,栈的构建和删除

(2)算法基本思想:

用二叉树来存储四则表达式,再通过后序遍历把中缀表达式转换为后缀表达式,最后通过栈来计算表达式的值,最后输出后序表达式和表达式的值。

(3)程序的流程:

该程序有三个模块组成:

1.输入模块:

输入一个中缀表达式

2.处理模块:

把中缀表达式转换为后缀表达式

3.计算模块:

计算表达式的值

4.输出模块:

输出后缀表达式及表达式的值

三.详细设计

(1)物理数据类型:

采用指针来实现二叉树,其中分支节点存储运算符,用叶子节点存储操作数,可以减少二叉树的结构性开销。

采用顺序栈来实现表达式的计算,建立一个栈S。

从左到右读后缀表达式,如果读到操作数就将它压入栈S中,如果读到n元运算符(即需要参数个数为n的运算符)则取出由栈顶向下的n项按操作符运算,再将运算的结果代替原栈顶的n项,压入栈S中。

如果后缀表达式未读完,则重复上面过程,最后输出栈顶的数值则为结束。

伪代码:

二叉树的基本操作伪代码:

后序遍历:

template

voidnextorder(BinNode*subroot)

{

if(subroot==Null)returnfalse;//Emptysubtree,donothing

nextorder(subroot->left());

visit(subroot);//Performwhateveractionisdesired

nextorder(subroot->right());

}

二叉树的建立:

//Binarytreenodeclass

template

classBinNodePtr:

publicBinNode

{

private:

Elemit;//Thenode'svalue

BinNodePtr*lc;//Pointertoleftchild

BinNodePtr*rc;//Pointertorightchild

public:

BinNodePtr()

{lc=rc=NULL;}

BinNodePtr(Eleme,BinNodePtr*l=NULL,BinNodePtr*r=NULL)

{

it=e;

lc=l;

rc=r;

}

Elem&val()

{returnit;}

voidsetVal(constElem&e)

{it=e;}

inlineBinNode*left()const

{returnlc;}

voidsetLeft(BinNode*b)

{lc=(BinNodePtr*)b;}

inlineBinNode*right()const

{returnrc;}

voidsetRight(BinNode*b)

{rc=(BinNodePtr*)b;}

boolisLeaf()

{return(lc==NULL)&&(rc==NULL);}

};

插入及删除:

InsertChild(T,p,LR,c);

DestroyBiTree(&T);

DeleteChild(T,p,LR);

顺序栈的基本操作及伪代码:

voidinit_stack()

{top=-1;}//空线性表初始化top

voidpush_stack(intx)

{s[top]=x;}//压栈:

voidpop_stack()

{top=top-1;}//出栈

inttop_stack()

{returns[top];}//取得栈顶元素

boolempty_stack()

{

if(top==-1)

returntrue;

else

returnfalse;

}//判断栈空

boolfull_stack()

{

if(top==3)

returntrue;

else

returnfalse;

}//判断栈满

intgetHeadStack()

{

returns[top];

}//返回栈顶元素的值

}

计算表达式的值:

Statusevaluate(charch[],float&result)

{

SqStackS;

StatusSt;

inti;

i=0;

St=InitStack(S);

while(ch[i]!

='#'&&i<100)

{

if(IsDigital(ch[i]))

{

i+=EvalValue(&ch[i],S);

}

elseif(ch[i]=='')

i++;

else{

EvalExpr(ch[i],S);

i++;

}

}

(2)算法的具体步骤:

首先建立一颗二叉树,用二叉树的分支节点存储四则运算的操作符,用二叉树的叶子节点存储二叉树的操作数,然后再对二叉树进行一次后序遍历,把后序遍历得到的压入栈中,当读到n元运算符时,则取出由栈顶向下的n项按操作符运算,再将运算的结果代替原栈顶的n项,压入栈中。

如果后缀表达式未读完,则重复上面过程,最后输出栈顶的数值则为结束。

(3)算法的时空分析:

采用二叉树中分支节点和叶子节点分别存储不同的数据类型,是算法的结构性开销明显降低,对二叉树进行一次后序遍历的时间代价为

,对顺序栈实行压栈和出栈时

,故计算表达式值时时间开销为

(4)输入输出格式:

Cout<<”请输入一串中缀表达式:

Cin>>21+23*(12-6)+9;

Cout<<”转换为后缀表达式时为:

”<

Cout<<2123126-*+9+<

Cout<<”表达式的值为:

”<

Cout<<168<

(5)结果截图:

(6)代码:

#include

#include

#include

#include

#include

#include

#defineSTACK_INIT_SIZE100

#defineDATA_SIZE10

#defineSTACKINCREMENT10

#defineOK1

#defineTRUE1

#defineFALSE0

#defineERROR0

#defineOVERFLOW-2

usingnamespacestd;

typedeffloatSElemtype;

typedefintStatus;

typedefchar*TElemType;

typedefstructBiTNode{

TElemTypedata;

intlen;//data字符串中字符的个数

structBiTNode*lchild,*rchild;

}BiTNode,*BiTree;

typedefstruct

{

SElemtype*base;

SElemtype*top;

intstacksize;

}SqStack;

StatusIsDigital(charch)

{

if(ch>='0'&&ch<='9')

{

return1;//是数字字母

}

return0;//不是数字字母

}

intCrtNode(stack&PTR,char*c)

{

BiTNode*T;

inti=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);

returni;

}

voidCrtSubTree(stack&PTR,charc)

{

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);

}

charsymbol[5][5]={{'>','>','<','<','>'},//符号优先级

{'>','>','<','<','>'},

{'>','>','>','>','>'},

{'>','>','>','>','>'},

{'<','<','<','<','='}};

intsym2num(chars)//返回符号对应优先级矩阵位置

{

switch(s)

{

case'+':

return0;break;

case'-':

return1;break;

case'*':

return2;break;

case'/':

return3;break;

case'#':

return4;break;

}

}

charPrecede(chara,charb)//返回符号优先级

{

return(symbol[sym2num(a)][sym2num(b)]);

}

voidCrtExptree(BiTree&T,charexp[])

{//根据字符串exp的内容构建表达式树T

stackPTR;//存放表达式树中的节点指针

stackOPTR;//存放操作符

charop;

inti=0;

OPTR.push('#');

op=OPTR.top();

while(!

((exp[i]=='#')&&(OPTR.top()=='#')))//与

{

if(IsDigital(exp[i]))

{//建立叶子节点并入栈PTR

i+=CrtNode(PTR,&exp[i]);

}

elseif(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();

}//endwhile

i++;

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;

}

}//endswitch

}//endelse

}//endwhile

T=PTR.top();

PTR.pop();

}

voidPostOrderTraverse(BiTree&T,char*exp,int&count)

{

//后序遍历表达式树T,获取树中每个结点的数据值生成逆波兰表达式exp

//T是表达式树的根节点;字符串exp保存逆波兰表达式;count保存exp中字符的个数

//后序遍历中,处理根结点时,依据T->len的值,把T->data中的字符依次添加到当前exp字符串的尾端

//添加完T->data后,再添加一个空格字符,同时更新count计数器的值。

//填空

//inti;

if(T)

{

PostOrderTraverse(T->lchild,exp,count);

PostOrderTraverse(T->rchild,exp,count);

strncpy(exp+count,T->data,T->len);

exp[count+=(T->len)]='';

count++;

}

}

 

//---------------------------------

//逆波兰表达式计算

//填空

StatusInitStack(SqStack&S)

{

S.base=(SElemtype*)malloc(STACK_INIT_SIZE*sizeof(SElemtype));

if(!

S.base)exit(OVERFLOW);

S.top=S.base;

S.stacksize=STACK_INIT_SIZE;

//printf("程序运行到构建栈\n");

returnOK;

}

intStackLength(SqStackS)

{

returnS.top-S.base;

//printf("程序运行到获得堆栈元素的个数\n");

//获得堆栈元素的个数

}

 

StatusPush(SqStack&S,SElemtypee)

{

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;

//printf("程序运行到入栈\n");

returnOK;

//入栈

}

StatusPop(SqStack&S,SElemtype&e)

{

if(S.top==S.base)

returnERROR;

e=*--S.top;

//printf("程序运行到出栈\n");

returnOK;

//出栈

}

intEvalValue(char*ch,SqStack&S)

{

inti=0;

SElemtyperesult=0;

chara;

a=ch[i];

while(IsDigital(a))

{

result=10*result+(int)(a-48);

a=ch[++i];

}

Push(S,result);

//printf("程序运行标志1\n");

returni;

}

voidEvalExpr(charch,SqStack&S)

{

floatp,q,r;

if((ch=='+')||(ch=='-')||(ch=='*')||(ch=='/'))

{

Pop(S,p);

Pop(S,q);

switch(ch)

{

case'+':

r=p+q;

break;

case'-':

r=q-p;

break;

case'*':

r=q*p;

break;

case'/':

if(p==0)

printf("输入错误!

!

!

!

");

else

r=q/p;

break;

default:

;

}

Push(S,r);

//printf("程序运行标志2\n");

}

//如果ch中保存的是操作符,则从堆栈中弹出两个元素,并把操作符应用在这两个元素之上,

//然后把操作结果压入到栈中。

如果试图从栈中弹出两个元素是,该栈中并没有,那么该

//后缀表达式是不正确的。

 

}

Statusevaluate(charch[],float&result)

{

SqStackS;

StatusSt;

inti;

i=0;

St=InitStack(S);

while(ch[i]!

='#'&&i<100)

{

if(IsDigital(ch[i]))

{

i+=EvalValue(&ch[i],S);

}

elseif(ch[i]=='')

i++;

else{

EvalExpr(ch[i],S);

i++;

}

}

//如果到达表达式末尾时,栈中剩余元素不止一个,那么该

//后缀表达式是不正确的。

if(StackLength(S)==1)

Pop(S,result);

else{

//printf("表达式错误");

returnERROR;

}

//printf("程序运行标志3\n");

returnOK;

}

 

//-------------------------

 

main()

{

BiTreeT;

StatusSt;

charch[100],c;//输入的四则运算表达式

charexp[100];//逆波兰表达式

intcount=0;

inti=0;

floatresult;

printf("请输入表达式:

\n");

while(i<100)

{

scanf("%c",&c);

ch[i++]=c;

if(c=='\n'){

ch[--i]='#';

break;

}//endif

}

CrtExptree(T,ch);//根据字符串ch的内容构建表达式树T

//后序遍历表达式树T得到表达式的逆波兰表达式exp;count中保存exp中字符的个数

PostOrderTraverse(T,exp,count);

printf("逆波兰表达式为:

\n");

for(i=0;i

printf("%c",exp[i]);

printf("\n");

exp[count]='#';//添加结束符

St=evaluate(exp,result);//计算逆波兰表达式exp的值

//输出计算的结果

if(St)

printf("运算结果:

%5.2f\n",result);

else

printf("\n表达式错误\n");

return0;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1