分享:中缀表达式转后缀表达式
写的一个简单的计算器,能简单+ - * / ^ 运算,没有考虑计算结果溢出问题。处理了负号运算,合法的负号。只能是第一个数为负数,左括号开头的第一个数为负数,以及括号括起来的负数。
希望各位大牛指点下哪里不足。
程序代码:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#define MAXSIZE 10000
struct Stackop
{
char op[MAXSIZE];
int top;
}Stackop;
struct Stacknum
{
double num[MAXSIZE];
int top;
}Stacknum;
int GetLevel(char op) //得到运算符优先级
{
if (op == '+' || op == '-')
return 1;
else if (op == '*' || op == '/')
return 2;
else if (op == '^')
return 3;
else
return -1;
}
double Caclulate(double a, double b, char symbol, int *flag)
{
switch (symbol) //数据运算,以及除数不能为0
{
case '+' :
return a + b;
case '-' :
return a - b;
case '*' :
return a * b;
case '/':
if (b == 0)
*flag = 0;
else
return a / b;
break;
case '^' :
return pow(a, b);
default :
*flag = 0;
break;
}
return 0;
}
int GetRpn(char *calc, char *rpn) //中缀表达式转后缀表达式
{
int len, i, flag, cnt, error;
error = flag = cnt = 0;
Stackop.top = -1; //字符栈为空
len = strlen(calc);
if (calc[len - 1] == '=') //考虑最后是否为=
calc[len - 1] = '\0';
for (i = 0; calc[i] != '\0'; i++) //将负数和-号区别,负数用!代替
if (calc[0] == '-' || calc[i] == '-' && calc[i - 1] == '(')
calc[i] = '!';
for (i = 0; calc[i] != '\0'; i++)
{
if (isdigit(calc[i]) || calc[i] == '!') //数字处理过程,如果扫描到的是数字,直接加入到后缀数组中
{
if (!isdigit(calc[i]))
{
i++;
flag = 1;
}
if (!isdigit(calc[i]))
return 0;
while (isdigit(calc[i]))
{
rpn[cnt++] = calc[i];
i++;
}
if (calc[i] == '.') {
rpn[cnt++] = calc[i];
++i;
while (isdigit(calc[i]))
{
rpn[cnt++] = calc[i];
i++;
}
}
if (flag)
{
rpn[cnt++] = '#'; //如果是负数末尾加#加!,表示一个负数结束
rpn[cnt++] = '!';
flag = 0;
}
else
{
rpn[cnt++] = '#'; //当是整数末尾加#,表示一个正数结束
}
}
if (calc[i] == '\0')
break;
if (calc[i] == '(') //如果是左括号直接进符号栈
Stackop.op[++Stackop.top] = calc[i];
else if (calc[i] == ')') { //当匹配到右括号出栈
while (Stackop.op[Stackop.top] != '(') //如果栈顶是左括号,直接结束,相当于空括号
{
rpn[cnt++] = Stackop.op[Stackop.top]; //挨个把括号里面的运算符转换到后缀数组中
--Stackop.top;
}
--Stackop.top; //把匹配到的左括号出栈
}
else if (Stackop.op[Stackop.top] != -1 && GetLevel(calc[i]) <= GetLevel(Stackop.op[Stackop.top]))
{ //扫描到的运算符如果比栈顶优先级低,栈里所有优先级低于扫描到运算符优先级的运算符
//加入到后缀数组
while (Stackop.op[Stackop.top] != -1 && (error = GetLevel(calc[i])) <= GetLevel(Stackop.op[Stackop.top]))
{
if (error == -1)
return 0;
rpn[cnt++] = Stackop.op[Stackop.top];
Stackop.top--;
}
Stackop.op[++Stackop.top] = calc[i]; //如果符号栈为空,或者栈里优先级大于扫描到的字符优先级,把扫描到的运算符加入字符栈
}
else
Stackop.op[++Stackop.top] = calc[i]; //字符栈空或者优先级比扫描到的运算符优先级大, 假如到字符栈
}
while (Stackop.top != -1) {
rpn[cnt++] = Stackop.op[Stackop.top]; //到最后字符栈还有运算符,一次加入到后缀数组,最后得到后缀表达式
Stackop.top--;
}
rpn[cnt] = '\0';
return 1;
}
int GetAns(char *rpn, double *result)
{
int i, flag = 1;
double num, cnt;
double a, b, val;
Stacknum.top = -1; //这里开始就是后缀表达式计算过程
for (i = 0; rpn[i] != '\0'; i++) //到这里就是入栈和出栈的过程,只要是数字就直接入栈;是字符,数字栈出栈两个元素进行运算后入栈
{ //反复此过程,到最后栈顶元素就只有一个,就是我们要的计算结果
if (rpn[i] >= '0' && rpn[i] <= '9') {
num = 0;
cnt = 1.0;
while (rpn[i] != '#' && rpn[i] != '.')
{
num = num * 10.0 + (rpn[i] - '0');
i++;
}
if (rpn[i] == '.')
{
i++;
while (rpn[i] != '#')
{
num = num * 10.0 + (rpn[i] - '0');
cnt *= 10;
i++;
}
}
if (rpn[i + 1] == '!')
{
i++;
Stacknum.num[++Stacknum.top] = num / cnt * (-1); //字符串转换为数字或者浮点数入数字栈
}
else
Stacknum.num[++Stacknum.top] = num / cnt;
}
else
{ //匹配到运算符,两个数字出栈参加运算再进栈
b = Stacknum.num[Stacknum.top--];
if (Stacknum.top == -1)
return 0;
a = Stacknum.num[Stacknum.top--];
val = Caclulate(a, b, rpn[i], &flag);
Stacknum.num[++Stacknum.top] = val;
}
}
*result = Stacknum.num[Stacknum.top];
if(!flag)
return 0;
return 1;
}
int main()
{
char calc[MAXSIZE], rpn[MAXSIZE];
double result;
while (1)
{
printf("Please input calculate expression and expression can't hava special symbols!\n\n");
scanf("%[^\n]%*c", calc); //表示读一行,解决scanf不能读空格的问题
if (!GetRpn(calc, rpn))
{
printf("\nError: expresion error!\n");
continue;
}
if (GetAns(rpn, &result))
printf("\nCalculate val = %lf\n\n", result);
else
printf("\nError: expresion error!\n");
}
return 0;
}[此贴子已经被作者于2017-5-28 09:42编辑过]









