—我们都知道计算一个复杂的算数表达式要遵从一定的约定(ps:先乘除后加减有括号先算括号等),而要编写一个程序来计算算数表达式就得你去自己规定运算顺序喽~
在这里将算数表达式转化为后缀表达式然后再进行运算是一个我认为比较便捷的方法。
先简单地解释一下后缀表达式:
转化为后缀表达式的方法为:
1.从左到右依次读取算式的一个字符
2.如果读到括号,则跳过,到下一个字符
3.如果读到的是数字,则直接输出到一个结果字符串的末尾(这个字符串就是最后要的后缀表达式)
4.如果读到的是运算符,则要将此运算符入栈
(1)若栈空,则直接入栈;
(2)若栈不空,则要判断栈顶运算符的优先级
<1>若栈顶运算符的优先级低于要入栈的运算符,直接入栈
<2>若栈顶运算符的优先级高于要入栈的运算符,要将栈顶运算符位置的高优先级的运算符出栈,出栈的运算符输出到结果字符串的末尾,直到栈顶运算符优先级低于要入栈的运算符为止。(实际就是要保证栈中的运算符优先级从栈顶到栈底是依次从高到低的)
5.依次按照上述方式读取,直到将中缀表达式读完。最后的结果就保存在这个结果字符串。
6.最后将栈中还有的运算符出栈,加入到结果字符串中去,就得到了后追表达式。
举个栗子:对于算式 1*2+(2-1) 此式子也叫中缀表达式
设结果字符串 char result[20];
设存储的栈为stack
第一个字符为1,直接加到结果字符串 result = ”1“;
第二个字符为*,栈为空,直接入栈。stack = *;
第三个字符为2,加入到结果字符串result = "12"
第四个字符为+, 栈不空,入栈,栈顶运算符优先级高于要入栈的运算符+,,故先出栈,加入到结果字符串result = “12*”
第五个字符为)直接跳过
第六个字符为2加入结果字符串result = 12*2
第七个字符为-,栈不空,入栈,栈顶运算符+优先级要高于入栈运算符-,故+先出栈,加入到结果字符串result = 12*2+
,然后入栈stack = -
第七个运算符为1,加入结果字符串result = 12*2+1
第八个字符为),跳过
到此中缀表达式读取完毕
后缀表达式为result = “12*2+1-”
第二个问题:后缀表达式的计算
1.将后缀表达式从左到右依次读取
2.如果读到数字直接入栈
3.如果读到运算符,则将栈顶的两个数字出栈,和此运算符做运算,再将计算的结果压入栈中。(注意:先入栈的数为减数,后入栈的数为被减数 用top减或除top-1,得到的结果压入top-1中)
4.重复上述步骤,最终的运算结果就存在栈里
举栗子:
上面得到的后缀表达式为:122+1-
设栈为stack
第一个字符为1,入栈stack=1
第二个字符为2,入栈stack=12
第三个字符为,栈元素做出运算1*2=2再入栈stack=2
第四个字符为2,入栈stack=22
第五个字符为+,栈元素出栈做运算2+2=4,再入栈stack=4
第六个元素1,入栈stack=41
第七个元素-,栈元素做出运算4-1,得到3,再将3入栈stack=3
到此为止,后缀表达式读取完毕,栈中就存储结果最终结果为3
具体代码实现为:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
struct OPTR
{
char data[MAXSIZE];
int top;
}OPTR;
struct OPRD
{
int data[MAXSIZE];
int top;
}OPRD;
//将算数表达式转化为后缀表达式
void postfix_exp_trans(char exp[], char postfix_exp[])//postfix_exp为得到的后缀表达式
{
char ch;
int i = 0, j = 0;
OPTR.top = -1;
ch = exp[i];
i++;
while(ch != '\0')
{
switch(ch)
{
case '(': //左括号
OPTR.top++; OPTR.data[OPTR.top]=ch;
break;
case ')': //右括号
while(OPTR.data[OPTR.top]!='(')
{
postfix_exp[j]=OPTR.data[OPTR.top];
j++;
OPTR.top--;
}
OPTR.top--;
break;
case '+'://+-优先级不大于栈顶任何运算符直到‘)’
case '-':
while(OPTR.top != -1 && OPTR.data[OPTR.top]!='(')
{
postfix_exp[j] = OPTR.data[OPTR.top]; j++;
OPTR.top--;
}
OPTR.top++;
OPTR.data[OPTR.top] = ch;
break;
case '*': //*或/时,其优先级不大于栈顶为‘*’'/'的优先级直到)
case '/':
// printf("%s\n",postfix_exp);
while(OPTR.top != -1 && OPTR.data[OPTR.top] != '(' && (OPTR.data[OPTR.top] == '*' || OPTR.data[OPTR.top] == '/'))
{
postfix_exp[j] = OPTR.data[OPTR.top];
j++;
OPTR.top--;
}
OPTR.top++;
OPTR.data[OPTR.top] = ch;
break;
case ' ':
break;
default:
while (ch>='0' && ch<='9')
{
postfix_exp[j]=ch; j++;
ch=exp[i]; i++;
}
i--;
postfix_exp[j]='#'; j++;
}
ch = exp[i];
i++;
}
while(OPTR.top != -1) //exp扫描完毕,栈不空时出栈并存放到postfix_exp中
{
postfix_exp[j] = OPTR.data[OPTR.top];
j++;
OPTR.top--;
}
postfix_exp[j]='\0'; //给后缀表达式添加结束标识符*/
}
int cale_exp(char postfix_exp[])
{
int d;
char ch;
int i = 0;
OPRD.top = -1;
ch = postfix_exp[i];
i++;
while(ch != '\0')
{
switch(ch)//运算时要注意减法和除法运算 先入栈为减数(除数),后入栈为被减数(被除数)
{
case '+':
OPRD.data[OPRD.top-1] = OPRD.data[OPRD.top]+OPRD.data[OPRD.top-1];
OPRD.top--;
break;
case '-':
OPRD.data[OPRD.top-1] = OPRD.data[OPRD.top-1]-OPRD.data[OPRD.top];
OPRD.top--;
break;
case '*':
OPRD.data[OPRD.top-1] = OPRD.data[OPRD.top]*OPRD.data[OPRD.top-1];
OPRD.top--;
break;
case '/':
if(OPRD.data[OPRD.top]!=0)
OPRD.data[OPRD.top-1] = OPRD.data[OPRD.top-1]/OPRD.data[OPRD.top];
else
{
printf("\t\t不能除零!\n");
exit(0);
}
OPRD.top--;
break;
default:
d = 0;
while(ch >= '0' && ch <= '9')
{
d = 10*d + ch-'0';
ch = postfix_exp[i];
i++;
}
OPRD.top++;
OPRD.data[OPRD.top] = d;
}
ch = postfix_exp[i];
i++;
}
return OPRD.data[OPRD.top];
}
int main()
{
// char exp[100];
char exp[20]="25-8+4/2*(80+20)";
char postfix_exp[100];
// scanf("%s",exp);
postfix_exp_trans(exp, postfix_exp);
printf("%d\n",cale_exp(postfix_exp));
return 0;
}