《数据结构》给出这样一道题目:
借助辅助栈,编写算法,计算一个后缀表示式T的值。
题目减少了将中缀表达式转换为后缀表达式的算法步骤。事实上,要实现四则运算求值,需要把中缀表达式转化为后缀表达式,再把后缀表达式进行运算得出结果。
一、中缀表达式与后缀表达式
1. 观察式子:1+2
平时我们所用的四则运算表达式都是运算符在两个数字中间的,所以称这种表达式为中缀表达式。它需要判断括号匹配,需要判断加减乘除的优先级。
2. 观察式子:1 2 +
运算符在两个数字之后的表达式为后缀表达式。
如果将式子「1」:6 + ( 4 - 2 ) × 3 + 9 ÷ 3
转化为式子「2」:6 4 2 - 3 × + 9 3 ÷ +
12 + 3 ==15
12 3 +==15
和式子「1」比,式子「1」中两个数字中间运算符在式子2中都在两个数字之后出现,称式子「2」为后缀表达式。后缀表达式不需要考虑括号匹配、运算符优先级,简化运算。
二、中缀表达式转后缀表达式
1. 利用栈的特性,给出转换方法
从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理。
① 运算数:直接输出;
② 左括号:压入堆栈;
③ 右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
④ 运算符:
•当优先级大于栈顶运算符时,则把它压栈;
•当优先级小于或等于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈;
⑤ 若各对象处理完毕,则把堆栈中存留的运算符一并输出。
2. 以中缀表达式:6 + ( 4 - 2 ) × 3 + 9 ÷ 3 转后缀表达式为例
三、后缀表达式的运算
1. 规则:(用栈来进出运算的数字)
① 从左到右遍历中缀表达式的每一个数字和符号
② 若是数字,则进栈
③ 若是符号,则把处于栈顶的两个数字出栈,进行运算
④ 运算结果进栈
⑤ 直到获得最终结果
2. 以计算后缀表达式:6 4 2 - 3 × + 9 3 ÷ + 为例
四、算法的实现
算法需要两个栈,stack1 存放运算数 (num),stack2 存放运算符 (operator) 。分配空间、初始化这两个栈。
接口除了栈的基本操作外,还需要这些操作:判断、比较运算符的优先级、两数四则运算。用户输入的数据为中缀表达式,以%s的格式输入到 str ,循环遍历 str 的每一个字符,完成数字入栈、比较运算符的优先级等,还要注意第一个数是负数的特殊情况,注意用户错误输入的情况 。详细代码在本文暂略,可以参考:
https://github.com/wmsofts/Calculator_V1
https://github.com/wmsofts/Calculator_V2
https://github.com/wmsofts/Calculator_V3
(代码存在不完善的地方)
五、
对于题目:编写算法,计算一个后缀表示式T的值。简略代码如下:
1. 定义栈:
/*顺序栈的类型定义 */
typedef struct{
ElemType *elem;
int *top;
int size;
int increment; //扩容时,增加的存储容量
}SqStack;
SqStack S;
Status Input(char m[MAXSIZE]){
int h = 0;
for(; m[h - 1] != '#'; h++){ //输入以#结束
m[h] = getchar();
}
m[h] = '\0';
return OK;
}
Status Calc(char m[MAXSIZE])
{
int h = 0;
int g = 0;
for(; m[h] != '#'; h++){
int k;
char j;
if(m[h] >= '0' && m[h] <= '9'){
g = g * 10 + m[h] - '0';
}
else
if((m[h] == ' ' || m[h] == '+' || m[h] == '-' || m[h] == '/' || m[h] == '*') && m[h-1] >= '0' && m[h-1] <= '9'){
k = g;
g = 0;
Push(S, k);
}
if(m[h] == '+' || m[h] == '-' || m[h] == '/' || m[h] == '*')
goto area;
else{
area: j = m[h];
switch(j){
case '+':{
int c;
c = Pop(S);
int d;
d = Pop(S);
Push(S, d + c);
break;
}
case '-':{
int c;
c = Pop(S);
int d;
d = Pop(S);
Push(S, d - c);
break;
}
case '*':{
int c;
c = Pop(S);
int d;
d = Pop(S);
Push(S, d * c);
break;
}
case '/':{
int c;
c = Pop(S);
int d;
d = Pop(S);
Push(S, d / c);
break;
}
default:
break;
}
}
}
return OK;
}
调用:
int main(){
InitStack(S);
char m[MAXSIZE];
Input(m);
Calc(m);
int result = Pop(S);
cout << result << endl;
}
————————————————————————
2. 如果这样定义栈,
typedef struct STRACK
{
double a[100];
int top;
} STRACK;
代码可以改为:
int main()
{
double totle=0,e=0;
char s[100];
int i;
STRACK L;
L.top=-1;
gets(s);
for(i=0; s[i]!='@'; i++)
{
if(s[i]<='9'&&s[i]>='0')
{
L.top++;
int temp=s[i]-'0';
int k=i+1;
while(s[k]!='@') //利用while循环得到由多位由字符组成的数值
{
if(s[k]<='9'&&s[k]>='0')
{
temp=10*temp+(s[k]-'0');
i++;
k++;
}
else break;
}
L.a[L.top]=temp;
}
else if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/') //遇到运算符进行计算
{
switch(s[i])
{
case '+':
e=L.a[L.top-1]+L.a[L.top];
break;
case '-':
e=L.a[L.top-1]-L.a[L.top];
break;
case '*':
e=L.a[L.top-1]*L.a[L.top];
break;
case '/':
e=L.a[L.top-1]/L.a[L.top];
break;
}
L.a[L.top-1]=e; //往前一位存储
L.a[L.top]=0;
L.top--;
}
}
printf("%.0lf",L.a[L.top]); //输出最后结果
return 0;
}