【问题描述】
在计算机中,算术表达式由常量、变量、运算符和括号组成。由于不同的运算符具有不同的优先级,又要考虑括号,因此,算术表达式的求值不可能严格地从左到右进行。因而在程序设计时,借助栈实现。
【任务要求】
算法输入:一个算术表达式,由常量、变量、运算符和括号组成(以字符串形式输入)。为简化,规定操作数只能为正整数,操作符为+、-*、/,用#表示结束。
算法输出:表达式运算结果。
算法要点:设置运算符栈和运算数栈辅助分析算符优先关系。在读入表达式的字符序列的同时,完成运算符和运算数的识别处理,以及相应运算。
问题分析
如果此类问题只需要计算10以内的数字运算,会非常简单。这里不再赘述。然而当需要计算多位数的计算时,例如123+(23-11)*113-45/3=?,当输入为字符串时,需要将表达式中运算数分离出来,并且利用负数代替其中的运算符。
本代码,借助《数据结构(C语言版)》(严蔚敏著)书中的53页算法,及其中关于运算符优先级的表格。
//2017 1 2 wangran 赵海航
//这个不能计算负数
//表达式中也不要出现0
#include<stdio.h>
#include<malloc.h>
#include<math.h>
float num[100]={0};
//使用-1,-2,-3,-4,-5,-6,-7,分别代表,+,-,*,/,(,),#
//使用-1,0,1分别代表<,=,>
int operate[8][8]={0, 0, 0, 0, 0, 0, 0, 0,//书p53表格
0, 1, 1,-1,-1,-1, 1, 1,
0, 1, 1,-1,-1,-1, 1, 1,
0, 1, 1, 1, 1,-1, 1, 1,
0, 1, 1, 1, 1,-1, 1, 1,
0,-1,-1,-1,-1,-1, 0, 0,
0, 1, 1, 1, 1, 0, 1, 1,
0,-1,-1,-1,-1,-1, 0, 0,
};
struct StackNode{
float data;
struct StackNode *next;
};
struct LinkStack{
struct StackNode *top;
float length;
};
struct LinkStack * InitStack ()//初始化栈结构
{
struct LinkStack *S;
S=(struct LinkStack *)malloc(sizeof(struct LinkStack));
S->top=NULL;
S->length=0;
return S;
}
void Push(struct LinkStack * S,float e)//入栈
{
struct StackNode *p;
p=(struct StackNode*)malloc(sizeof(struct StackNode));
p->data=e;
p->next=S->top;
S->top=p;
S->length++;
}
void Pop(struct LinkStack *S)//出栈
{
struct StackNode *p;
p=(struct StackNode*)malloc(sizeof(struct StackNode));
p=S->top;
S->top=S->top->next;
S->length--;
free(p);
}
float GetTop(struct LinkStack *S)//获得栈顶元素
{
float e;
e=S->top->data;
return e;
}
int StackEmpty(struct LinkStack *S)//判断是否为空栈
{
return !(S->length);
}
void getnum()//将字符转化为整形数
{
char c;
int temp=0,temp2=0;
int index=0;
while((c=getchar())&&c!='\n')
{
if (isdigit(c))//如果是数字
{
temp=temp*10+(c-'0');
}
else
{
if (c=='+')
{
temp2=-1;
}
else if (c=='-')
{
temp2=-2;
}
else if (c=='*')
{
temp2=-3;
}
else if (c=='/')
{
temp2=-4;
}
else if (c=='(')
{
temp2=-5;
}
else if (c==')')
{
temp2=-6;
}
else if (c=='#')
{
temp2=-7;
}
}
if (temp!=0&&temp2!=0)//此处我目前只想到这么写,
{
num[index++]=temp;
num[index++]=temp2;
temp=temp2=0;
}
else if (temp==0&&temp2!=0)
{
num[index++]=temp2;
temp2=0;
}
}
}
int precede(float a,float b)//获取a,b的优先级
{
a=(int)(fabs(a));
b=(int)(fabs(b));
int n=a;
int m=b;
return operate[n][m];
}
float OPERATE(float a,float theta,float b)//对于a,b操作
{
switch((int)theta)
{
case -1:return a+b;
case -2:return a-b;
case -3:return a*b;
case -4:return a/b;
}
}
float operandTypeEvaluateExperssion ()//计算函数,此算法使用使用书中53页
{
int i=0,c;
float a,b,theta,x;
struct LinkStack *OPTR,*OPND;
OPTR=InitStack();
OPND=InitStack();//初始化
Push(OPTR,-7);
c=num[i];
while(c!=-7||GetTop(OPTR)!=-7)
{
if (c>=0)
{
Push(OPND,c);
c=num[++i];
}
else
{
switch(precede(GetTop(OPTR),c))
{
case -1:
Push(OPTR,c);
c=num[++i];
break;
case 0:
//Pop(OPTR,x);
x=GetTop(OPTR);//这里由于不能使用引用操作,所以用gettop和pop代替书中的引用
Pop(OPTR);
c=num[++i];
break;
case 1:
//Pop(OPTR,theta);
theta=GetTop(OPTR);
Pop(OPTR);
// Pop(OPND,b);
b=GetTop(OPND);
Pop(OPND);
//Pop(OPND,a);
a=GetTop(OPND);
Pop(OPND);
Push(OPND,OPERATE(a,theta,b));
break;
}//switch
}
}//while
return GetTop(OPND);
}
int main()
{
getnum();
// int i;
// for (i=0;i<20;i++)
// printf("%d ",num[i]);
printf("\n结果为:%f\n",operandTypeEvaluateExperssion());
}
结果如图:
注:
此程序关键地方在于getnum()函数。