计算机中前缀中缀后缀表达式是数据结构栈的重要应用,他们都是对表达式的记法,只是相对位置不一样,顾名思义,前缀表达式指的是符号都在操作数之前,中缀表达式指的是运算符都在操作数之后,而后缀表达式是之后。如:
(a+b)*c-d是中缀表达式
-*+abcd是前缀表达式
ab+c*d-是后缀表达式
中缀表达式是我们常用也是人常见的一种记法,但对于计算机来说处理很复杂,一般都是先转换成前缀或者后缀表达式再进行计算。
一、利用后缀表达式求值:
计算机利用后缀表达式求值过程可分析如下:
以中缀(3+4)*5-6为例,转换成后缀是34+5*6-
从左向右扫描,遇到数字时,将数字压入栈,遇到运算符时候,把栈内前两个数字弹出,进行相应运算,并将计算结果入栈。重复直到表达式右端。
从左向右扫描。将数字3,4入栈;
遇见运算符+,弹出3,4,计算得7入栈
继续扫描,将5入栈
与运算符*,将7,5弹出计算,得35入栈
继续扫描,遇见6入栈
遇见运算符-,弹出两个35,6,计算得29入栈
到最右端,停止,所得结果29
下面关键就是如何把中缀表达式转换成后缀表达式:
1、初始化两个栈,运算符栈S1和数据栈S2
2、从左向右扫描中缀表达式,遇见数字直接入栈S2
3、遇见运算符,将比较运算符与S1栈顶运算符优先级
3-1、如果S1栈顶是空或者是或者是左括号则直接将遇见的运算符入栈S1
3-2、如果S1栈顶不是空也不是左括号,且遇见的运算符比S1内优先级要高,那么将该运算符直接入栈S1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况)
3-3、如果S1栈顶是是右括号或者优先级更大。则将S1内运算符出栈到S2里,再转回3-1
4、遇见括号
4-1、如果是遇见左括号,那么左括号运算符直接入栈S1
4-2、如果是遇见右括号,那么右括号运算符直接入栈S1
5、重复2-4,直至到表达式最右边
6、将S1中剩余运算符弹出到S2
7、 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。
将中缀表达式exp转换为后缀表达式,采用了一个op运算符栈,其他的用数组存储。
const int N=20;
vector inexpTopost(char a[],int n){
vector res;
char st[N];
int top=-1;
int i=0;
char c=a[i];
while(c!='\0'){
switch(c){
case '(':{top++;st[top]=c;break;}
case ')':{while(st[top]!='('){res.push_back(st[top]);top--;}
top--;
break;
}
case '+':
case '-':{while(top>-1&&st[top]!='('){res.push_back(st[top]);top--;}
top++;st[top]=c;
break;
}
case '*':
case '/':{
while(top>-1&&st[top]!='('&&(st[top]=='*'||st[top]=='/')){res.push_back(st[top]);top--;}
top++;st[top]=c;
break;
}
default:{
while(c>='0'&&c<='9')
{res.push_back(c);i++;c=a[i];}//装入多位的整数
i--;
res.push_back('#');//用标识表述数值结束
}
}
i++;c=a[i];
}
while(top>-1){res.push_back(st[top--]);}
return res;
}
在计算后缀表达式过程中采用一个数值栈st:
float getkey_post(vector arr){
int num_stack[N];int top1=-1;
int len=arr.size();
int i=0;
char c=arr[i];
int s=0;
while(i='0'&&c<='9'){s=10*s+c-'0';i++;c=arr[i];}
top1++;num_stack[top1]=s;i--;
}
}
i++;
}
return num_stack[top1];
}
二、利用前缀表达式求值
以中缀(3+4)*5-6为例,转换成前缀是-*+3456
利用前缀表达式求值:从右向左搜索,遇见数字时入栈,遇见运算符时候出栈前两个数字3+4=7,计算好7再入栈,遇见运算符*,出栈前两个进行计算7*5=35,再入栈,遇见运算符-,出栈进行运算35-6=29,入栈保存结果。
将中缀表达式转换为前缀的过程:
1、初始化两个栈,运算符栈S1和数据栈S2
2、从右向左扫描中缀表达式,遇见数字直接入栈S2
3、遇见运算符,将比较运算符与S1栈顶运算符优先级
3-1、如果S1栈顶是空或者是或者是又括号则直接将遇见的运算符入栈S1
3-2、如果S1栈顶不是空也不是左括号,且遇见的运算符比S1内优先级要高或者一样,那么将该运算符直接入栈S1。
3-3、如果S1栈顶是是左括号或者优先级更大。则将S1内运算符出栈到S2里,再转回3-1
4、遇见括号
4-1、如果是遇见右括号,那么左括号运算符直接入栈S1
4-2、如果是遇见左括号,那么右括号运算符直接入栈S1
5、重复2-4,直至到表达式最左边
6、将S1中剩余运算符弹出到S2
7、 依次弹出S2中的元素并输出,结果即为中缀表达式对应的前缀表达式。
vector inexpTopre(char a[],int n){
vector res;
char num_stack[N];int top1=-1;
char op_stack[N];int top2=-1;
int i=n-1;
char c=a[i];
while(i>=0){
switch(c){
case ')':{top2++;op_stack[top2]=c;break;}
case '(':{while(op_stack[top2]!=')'){top1++;num_stack[top1]=op_stack[top2];top2--;}
top2--;
break;
}
case '+':
case '-':{while(top2>-1&&op_stack[top2]!=')'&&(op_stack[top2]=='*'||op_stack[top2]=='/')){top1++;num_stack[top1]=op_stack[top2];top2--;}
top2++;op_stack[top2]=c;
break;
}
case '*':
case '/':{top2++;op_stack[top2]=c;
break;
}
default:{
while(c>='0'&&c<='9'){top1++;num_stack[top1]=c;i--;c=a[i];}
top1++;num_stack[top1]='#';i++;
}
}
i--;if(i<0)break;
c=a[i];
}
while(top2>-1){top1++;num_stack[top1]=op_stack[top2--];}
for(i=top1;i>=0;i--)
res.push_back(num_stack[i]);
return res;
}
最后是根据前缀序列求出最终结果:
int getvalue(char str[]){
int s=0;
int i,j;
int len=0;
for(i=0;str[i]!='\0';i++)
len++;
for(i=0,j=len-1;iarr){
int st[N],top=-1;
int len=arr.size();
int i=len-1,j;
char c=arr[i];
int s;
char tmp[N];
while(i>=0){
c=arr[i];
switch(c){
case '+':{st[top-1]=st[top]+st[top-1];top--;break;}
case '-':{st[top-1]=st[top]-st[top-1];top--;break;}
case '*':{st[top-1]=st[top]*st[top-1];top--;break;}
case '/':{
if(st[top-1]==0){cout<<"除数是0";return 0;}
st[top-1]=st[top]/st[top-1];top--;break;
}
case '#':break;
default:{
s=0;
j=0;
while(c>='0'&&c<='9'){tmp[j++]=c;i--;c=arr[i];}
tmp[j]='\0';s=getvalue(tmp);
top++;st[top]=s;i++;
}
}
i--;
}
return st[top];
}