写在最前面:想要实现带有符号优先级的计算器,比较常用的方法是将中缀表达式转化为后缀表达式进行运算。所谓的中缀表达式就是我们平时写的计算式,例如1+2,(2+3)3之类的,而后缀表达式则是把运算符放在运算数字时候的表达方式。
后缀表达式
定义:不包括括号,运算符放在两个运算数之后,计算顺序按照严格的从左到右,不考虑符号的优先级。
例如:我们吧1+2+3转化为后缀表达式应该是12+3+。计算时先算1+2=3,后缀表达式变为33+,再计算3+3=6即为得数。
算法思路
我用了两个栈,一个数字栈,一个符号栈,顾名思义,数字栈用来存操作数,符号栈用来存运算符。这里提出符号优先级的概念,之所以*号和+号同时存在的时候要先算*,就是因为乘号的优先级要高于加号。
这里将主要算法分为几部分:
- 如果输入的是数字就直接压入数字栈
- 如果输入的是左括号“(”,就直接压入符号栈,我们认为左括号是优先级最低的。
- 如果输入的是右括号“)”,就向前寻找左括号,直至将括号中间的所有符号全部弹出运算。
- 如果输入的是“+”,“-”,就要从符号栈栈顶开始,把所有优先级大于等于“+”“-”的符号弹出进行运算。
- 如果输入的是“*”“/”,就看符号栈栈顶是否是优先级等于“*”“/”,如果是的话则需要弹出运算。
这些步骤你都可以手算一下看看得数是否正确,很容易验算。
值得注意的细节
- 目前我这个程序只能对整数进行运算,无法对浮点数进行运算,后续可能会改进
- 除法可能会产生小数,我这里做的粗精度处理,直接保留为int型
- 对第一位是负数的应该进行特殊处理
- 对除数是0的应该进行特殊处理
栈
代码中所有栈我都用的C++STL标准库中的stack容器进行处理,相对手写的栈便捷许多,如果对stack容器不了解,可以移步C++中STL标准库——stack
代码实现
#include<stdio.h>
#include<stdlib.h>
#include<stack>
#include<iostream>
#include<string.h>
using namespace std;
stack<int> q1;//数字栈
stack<char> q2;//符号栈
int flag=0;//用来判断第一位是‘-’的情况
int flag2=0;//用来判断第一位是‘-’的情况
int flag1=0;//用来判断除数是0的情况
//取出数字栈顶两个数字进行s运算函数,需要注意!因为我们需要对数字栈进行入
//栈出栈操作,改变了数字栈的结构,所以我们需要在栈名前加“&”
void calculate(stack<int> &q1,char s)
{
int x,y,z;
switch(s)
{
case '+':
{
x=q1.top();
q1.pop();
y=q1.top();
q1.pop();
z=x+y;
q1.push(z);
break;
}
case '-':
{
x=q1.top();q1.pop();
y=q1.top();q1.pop();
z=y-x;
q1.push(z);
break;
}
case '*':
{
x=q1.top();q1.pop();
y=q1.top();q1.pop();
z=x*y;
q1.push(z);
break;
}
case '/':
{
x=q1.top();q1.pop();
y=q1.top();q1.pop();
if(x==0)
{
flag1=1;
break;
}
z=y/x;
q1.push(z);
break;
}
}
}
//用数字来表示符号优先级
int fuhao(char s)
{
if(s=='+'||s=='-')
return 1;
if(s=='*'||s=='/')
return 2;
if(s=='('||s==')')
return 3;
if(s=='#')
return -1;
}
//对两个栈进行入栈出栈以及计算的函数
void function(char a[100])
{
q2.push('#');//在符号栈先入一个“#”,防止后序找栈顶为空的时候发生异常
int len=strlen(a);
if(a[0]=='-')//如果第一个数字是负号的情况,要单独考虑
{
flag2=1;
a[0]='0';
}
for(int i=0;i<len;i++)//主循环
{
if(a[i]=='(')
{
q2.push(a[i]);
}
else if(a[i]==')')
{
while(q2.top()!='(')
{
calculate(q1,q2.top());
q2.pop();
}
q2.pop();
}
else if(a[i]>='0'&&a[i]<='9')
{
int num=0;
//数字不一定只有一位,如果是多位数字要进行处理
while(a[i]>='0'&&a[i]<='9')
{
num*=10;
num+=(a[i]-'0');
i++;
}
i--;
if(flag2==1&&flag==0)//对第一位是负数的单独处理
num*=-1;
q1.push(num);
flag=1;
}
else
{
if(a[i]=='+'||a[i]=='-')
{
if((fuhao(q2.top())>=fuhao(a[i]))&&q2.top()!='(')
{
while(fuhao(q2.top())>=fuhao(a[i])&&q2.top()!='(')
{
calculate(q1,q2.top());
q2.pop();
}
q2.push(a[i]);
}
else
{
q2.push(a[i]);
}
}
else if(a[i]=='*'||a[i]=='/')
{
if(fuhao(q2.top())==fuhao(a[i]))
{
calculate(q1,q2.top());
if(flag1==1)
{
printf("error");
return;
}
q2.pop();
q2.push(a[i]);
}
else
{
q2.push(a[i]);
}
}
}
}
//对栈中剩余数字进行处理,当字符栈空了自然运算就结束了
while(q2.top()!= '#')
{
calculate(q1,q2.top());
if(flag1==1)
{
printf("error");
return;
}
q2.pop();
}
printf("%d",q1.top());
}
int main()//主函数
{
char a[100];
scanf_s("%s",a,100);
function(a);
return 0;
}