中缀表达式转后缀表达式并求值讲解(源码)
我自己比较清楚刚学的时候的敲代码的无从下手的感觉,所以下面有源代码
如果清楚转换的规则,直接去看代码
不然还是,先捋清楚规则,在看代码,否则看不懂
中缀表达式转后缀表达式,手写的话很简单,用括号法就可以,下面随便找一个式子
为什么找这样一个式子呢?
因为它可以解释一个问题,就是中缀表达式转后缀表达式,结果不唯一
①根据运算顺序加括号
( ( ( a + b ) + ( c * d ) ) / e )
②把运算符移到相应括号的后面
( ( ( a b ) + ( c d ) * ) + e) / 注意中间的那个“+”不是原来的,看颜色区分
那么结果就是
"a b + c d * + e / "
下面我们换一个运算顺序
这样加括号 ( ( a + ( b + ( c * d ) ) )/ e )
那么结果就会变成
"a b c d * + + e / "
手写就是这么简单,但是计算机转化却没这么容易,因为没有人这么智能。
中缀用栈转后缀的规则
对于计算机来说,式子求值更好算的是后缀表达式,我们一般中缀表达式转为后缀表达式,
采用栈来完成
用代码转化之前,首先得知道代码转化过程中的规则
一般需要两个栈,一个用来过渡s1,一个存储结果s2,还有一个中缀表达式的字符数组mid(有数字有字符,所以使用字符数组)
规则:①如果当前mid[i]是数字,直接进入结果栈
②如果mid[i]是 ’ ( ',直接进入过程栈
③如果mid[i]是“+ - * / ”,那么就要进行判断(1和2是或的关系)
1.如果当前过程栈s1是空的,即top1==-1,mid[i]直接进入过程栈s1
2.如果当前mid[i]运算符的优先级大于s1栈顶的运算符优先级,直接进入过程栈s1
3.如果当前mid[i]运算符的优先级小于等于于s1栈顶的运算符优先级,则对s1进行出栈存到s2,直到mid[i]的优先级大于s1的栈顶。然后将mid[i]存到s1。
④如果当前mid[i]是 ’ ) ',则对s1进行出栈存到s2,直到遇见‘( ’, ‘(’直接出栈,不存到s2
最后输出s2就可以了
下面直接看源码,我根据自己的理解所写,可能会有所冗余
#include<iostream>
#include<cstdio>
#define maxSize 20
using namespace std;
int com(char c) //判断优先级的函数
{
if(c=='*'||c=='/')
return 2;
else if(c=='+'||c=='-')
return 1;
else if(c=='(')
return 0;
}
void change(char mid[],char s2[],int &top2) //中缀转后缀的函数
{ //因为需要输出s2,记录top2的改变,所以top2用引用传参
char s1[maxSize];int top1=-1; //定义过程栈
int i=0;
while(mid[i]!='\0')
{
if(mid[i]>='0'&&mid[i]<='9')
{
s2[++top2]=mid[i];
i++; //每一次处理完当前的mid【i】,要i++,不要忘记
}
else if(mid[i]=='(')
{
s1[++top1]=mid[i];
i++;
}
else if(mid[i]=='+'||mid[i]=='-'||mid[i]=='*'||mid[i]=='/')
{
if(top1==-1||s1[top1]=='('||com(mid[i])>com(s1[top1]))
{
s1[++top1]=mid[i];
}
else
{
while(com(mid[i])<=com(s1[top1]))
{
s2[++top2]=s1[top1--];
}
s1[++top1]=mid[i];
}
i++;
}
else if(mid[i]==')')
{
while(s1[top1]!='(')
{
s2[++top2]=s1[top1--];
}
top1--;
i++;
}
}
while(top1!=-1)
{
s2[++top2]=s1[top1--]; //如果处理完mid【i】,s1不为空,全部出栈存到s2
}
}
int main()
{
char mid[20];char s2[20];int top2=-1;
gets(mid);
change(mid,s2,top2);
int i=0;
while(i!=top2+1) //输出s2
{
cout<<s2[i++];
}
return 0;
}
全部代码就是这样。
后缀表达式求值
后缀表达式求值,一般都是用栈来完成的,且运算数都是一位
过程也很简单从左到右依次遍历后缀表达式,遇到数字直接压入栈中,遇到运算符,依次取出栈顶的两个数字,进行运算。先出来的是右运算数,次之是左云算数
下面是源码
#include<iostream>
#include<cstdio>
#define maxSize 30
using namespace std;
int com(int a, char op, int b)
{
if(op=='+')
return a+b;
else if(op=='-')
return a-b;
else if(op=='*')
return a*b;
else if(op=='/')
{
if(b==0) //除数是0的情况需要判断
{
cout<<"error";
return 0;
}
else
return a/b;
}
}
int cal(char bh[])
{
int i=0,a,b;
char op;
int stack[maxSize];
int top=-1;
while(bh[i]!='\0')
{
if(bh[i]>='0'&&bh[i]<='9')
{
stack[++top]=bh[i]-'0'; //将字符数字转换成整数类型压入栈中
i++;
}
else
{
op=bh[i]; //遇到运算符
b=stack[top--]; //取出数字
a=stack[top--];
stack[++top]=com(a,op,b); //调用运算函数,将计算结果压入栈中
i++;
}
}
return stack[top];
}
int main()
{
char bh[maxSize];
gets(bh);
int result=cal(bh);
cout<<result;
}