题目来源:codeup contest ID:100000605
后缀式的求值可以用栈来解决,于是我们需要把输入的中缀表达式改成后缀。
注:计算器1.0不够成熟只能实现操作数在10以内的运算
中缀转后缀
// void trans(char infix[], char s2[], int &top2)
{
char s1[maxSize];//存运算符辅助栈
int top1 = -1;
int i=0;
while(infix[i] !='\0')
{
if('0'<=infix[i]&&'9'>=infix[i])
{
s2[++top2]=infix[i];
++i;
}
else if (infix[i]=='(')
{
s1[++top1]='(';
++i;
}
else if(infix[i]=='+'||
infix[i]=='-'||
infix[i]=='*'||
infix[i]=='/')
{
if(top1==-1||
s1[top1]=='('||
getpriority(infix[i])>getpriority(s1[top1]))
{
s1[++top1]=infix[i];
++i;
}
else
s2[++top2]=s1[top1--];
}
else if(infix[i]==')')
{
while (s1[top1]!='(')
s2[++top2] = s1[top1--];
--top1;//出栈左括号
++i;
}
}
while (top1 !=-1)
s2[++top2] = s1[top1--];//出栈辅助栈剩余表达式
}
运算函数
double op(double a,double Op,double b)//运算函数
{
if(Op=='+') return a+b;
if(Op=='-') return a-b;
if(Op=='*') return a*b;
if(Op=='/')//题目是非负整数
{
if(b==0)
{
printf("error\n");
return 0;
}
else
return a/b;
}
}
double cal(char exp[])//后缀式计算函数
{
int i;
double a,b,c;
double stack[maxSize]; int top=-1;
char Op;
for(i=0;exp[i]!='\0';++i)
{
if(exp[i]>='0'&&exp[i]<='9')
stack[++top]=exp[i]-'0';
else
{
Op=exp[i];
b=stack[top--];
a=stack[top--];//后进先出
c = op(a,Op,b) ;
stack[++top]=c;
}
}
return stack[top];
}
主函数
int main()
{
char infix[maxSize];
gets(infix);
char rinfix[maxSize]={0};
int top2=-1;
trans(infix,rinfix,top2);
printf("%.2f",cal(rinfix));
return 0;
}
至此,仅能实现10以内运算数的计算(类似10/30就会出错)
- List item
改进计算函数
由于使用的是数组顺序栈,所以对于不同操作数的界限划分不够明显,于是想到用结构体栈
// An highlighted block
struct infix_Num
{
int datas[MAX];
int top;
};
更新:计算器2.0(实现带括号且操作数超过十的四则运算)
在上云实习的时候想了一下怎么修改,先贴个成品吧
// An highlighted block
#include<cstdio>
#define maxSize 50
int getpriority(char m)//获取运算符优先级
{
switch(m)
{
case'+':
case'-':
return 1;
break;
case'*':
case'/':
return 2;
break;
}
}
int trans(char infix[], double s2[], int &top2)//中缀转后缀函数,注意返回值是int,一个小巧思
{
double s1[maxSize];//存运算符的辅助栈
int top1 = -1;
int i=0;
int k=0;//用于记录后缀表达式的长度,并作为返回值返回
while(infix[i] !='\0')
{
if('0'<=infix[i]&&'9'>=infix[i])
{
s2[++top2]=infix[i]-'0';
++i;++k;
while('0'<=infix[i]&&'9'>=infix[i])
{
s2[top2]=infix[i]-'0'+s2[top2]*10;
i++;
}
}
else if (infix[i]=='(')
{
s1[++top1]='('-50;
++i;
}
else if(infix[i]=='+'||
infix[i]=='-'||
infix[i]=='*'||
infix[i]=='/')
{
if(top1==-1||
s1[top1]=='('-50||
getpriority(infix[i])>getpriority(s1[top1]+50))
{
s1[++top1]=infix[i]-50;
++i;
}
else
{
s2[++top2]=s1[top1--];
++k;}
}
else if(infix[i]==')')
{
while (s1[top1]!=('('-50))
{
s2[++top2] = s1[top1--];
k++;
}
--top1;//出栈左括号
++i;
}
}
while (top1 !=-1)
{s2[++top2] = s1[top1--];//出栈辅助栈剩余表达式
++i;++k;}
return k;
}
double op(double a,char Op,double b)//运算函数
{
if(Op=='+') return a+b;
if(Op=='-') return a-b;
if(Op=='*') return a*b;
if(Op=='/')//题目是非负整数
{
if(b==0)
{
printf("error\n");
return 0;
}
else
return a/b;
}
}
double cal(double exp[],int k)//后缀式计算函数
{
int i;
double a,b,c;
double stack[maxSize]; int top=-1;
char Op;
for(i=0;i<=k-1;++i)//k是长度,所以到k-1
{
if(exp[i]<0)
{
Op=exp[i]+50;
b=stack[top--];
a=stack[top--];//后进先出
c = op(a,Op,b) ;
stack[++top]=c;
}
else
stack[++top]=exp[i];
}
return stack[top];
}
int main()
{
char infix[maxSize];
gets(infix);
double rinfix[maxSize]={0};
int top2=-1;
int k =trans(infix,rinfix,top2);
printf("%.2f",cal(rinfix,k));
return 0;
}
总结
通过一系列改动实现了不借助结构体变量来进行带括号的四则运算(说白了有点偷懒不想改动太多哈哈哈,用结构体变量做起来肯定省心一些)
说说改动的几个关键点吧,顺便记录下思路
1、将输入的字符串存入一个double数组而不是通常的char数组
2、使用double数组是为了实现操作数大于十的运算,因为原来的程序前提是小于10(字符型)
3、为了区别double数组中的操作数与符号,符号入栈时将其减50(四则运算符号及括号ASCII均在40~50之间)
4、增加记录进栈元素个数的k以控制运算函数op的运算条件(现在想想好像用top2就行?)
在不断改进和完善的过程中更熟悉了顺序栈和调试的操作,要是愣找可能明年还在找bug吧2333
到此结束~