问题:算数运算的表达式求知
这道题不难,但是当你认真去编代码的时候,还是要考虑好多细节。
算法原理如下:
我们都知道算术四则运算的运算规则是:
先乘除,后加减。
从左到右计算
先算括号内,再算括号外
表达式组成
任何一个表达式都有操作数、运算符和界定符组成。
操作数即可以是常量,也可以是被说明为变量或常量的标识符。
运算符可以分为算术运算,关系运算和逻辑运算符。
界定符有左右括号和结束符等。
本文为了方便演示只使用算术运算。
运算符优先级
对于连个相继出现的操作符θ1和θ2 有三种关系:大于、等于和小于。由此可以列出“+-*/”之间的优先级。如下表:
| + | - | * | / | ( | ) | # | |
| + | > | > | < | < | < | > | > |
| - | > | > | < | < | < | > | > |
| * | > | > | > | > | < | > | > |
| / | > | > | > | > | < | > | > |
| ( | < | < | < | < | < | = | |
| ) | > | > | > | > | > | > | |
| # | < | < | < | < | < | = |
加减乘除优先性都低于“(”但是高于“)”,由运算从左到右可知,当θ1=θ2 ,令θ1>θ2
为了算法简洁,在表达式的左边和右边虚设一个“#”,这一对“#”表示一个表达式求值完成。
“(”=“)”当一对括号相遇时表示括号内已运算完成。
“)”和“(”、“#”和“(”、“(”和“#”无法相继出现如果出现则表达式出现语法错误。
为实现优先算法,可以使用两个工作栈,一个是OPTR,用于寄存运算符,一个是OPND,用于寄存运算数和运算结果。
代码如下:(存在一个bug)
#include<stdio.h> //表达式求值,顺序栈
#include<stdlib.h>
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define OK 1
#define ERROR 0
typedef int Status;
typedef struct{
char * base;
char * top;
int stacksize;
}SqStack;
//函数声明..................................
Status InitStack(SqStack &S); //符号栈的建立
Status Push(SqStack &S,char e); //入栈
void OperandType_EvaluateExpression(SqStack &OPND,SqStack &OPTR);
char GetTop(SqStack S); //返回栈顶元素
Status Pop(SqStack &S,char &e); //出栈
Status IsDigit(char c); //判断是否为数字
char Precede(char a,char e); //符号优先级判断,
int swap_char_to_int(char a); //在Precede中的字符转换为数字函数
char Operate(char a,char x,char b); //运算函数,返回为char型的数字
Status shownumbers(SqStack S);
//函数实现...........................................
Status InitStack(SqStack &S)
{
S.base = (char *)malloc(STACK_INIT_SIZE * sizeof(char));
if(!S.base)
exit(ERROR);
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}
Status Push(SqStack &S,char e)
{
if(S.top - S.base >= S.stacksize)
{
S.base = (char *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(char));
if(!S.base)
exit(ERROR);
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top = e;
S.top++;
return OK;
}
void OperandType_EvaluateExpression(SqStack &OPND,SqStack &OPTR)
{
char c;
char x;
char b;
char a;
Push(OPTR,'#');
c = getchar();
while(c != '#' || GetTop(OPTR) != '#')
{
if(IsDigit(c)) //若是数字则进数字栈,不是判断符号优先级
{
Push(OPND,c);
c = getchar();
}
else
{
switch(Precede(GetTop(OPTR),c))
{
case '<':
Push(OPTR,c);
c = getchar();
break;
case '=':
Pop(OPTR,x);
c = getchar();
break;
case '>':
Pop(OPTR,x);
Pop(OPND,b);
Pop(OPND,a);
Push(OPND,Operate(a,x,b));
break;
// printf("")
}
}
}
/* char sum;
sum = GetTop(OPND);
printf("%c\n",sum);
shownumbers(OPND);
printf("\n");
shownumbers(OPTR); */
}
char GetTop(SqStack S)
{
char e;
if(S.top == S.base)
exit(-1);
else
e = *(S.top-1);
return e;
}
Status Pop(SqStack &S, char &e)
{
if(S.base == S.top)
return ERROR;
else
e = *--S.top;
return OK;
}
Status IsDigit(char c)
{
if(c >= '0' && c <= '9')
return 1;
else
return 0;
}
char Precede(char a,char e)
{
int i,j;
int flag;
int symbol[7][7] = {
{0,0,1,1,1,0,0},
{0,0,1,1,1,0,0},
{0,0,0,0,1,0,0},
{0,0,0,0,1,0,0},
{1,1,1,1,1,2,4},
{0,0,0,0,4,0,0},
{1,1,1,1,1,4,2},
};
i = swap_char_to_int(a);
j = swap_char_to_int(e);
flag = symbol[i][j];
switch(flag)
{
case 0:return '>';
case 1:return '<';
case 2:return '=';
case 4:exit(-1);
}
}
int swap_char_to_int(char a)
{
switch(a)
{
case '+':return 0;
case '-':return 1;
case '*':return 2;
case '/':return 3;
case '(':return 4;
case ')':return 5;
case '#':return 6;
}
}
char Operate(char a,char x,char b)
{
int c,d;
int sum;
c = a-'0';
d = b-'0';
switch(x)
{
case '+':sum = c+d;break;
case '-':sum = c-d;break;
case '*':sum = c*d;break;
case '/':sum = c/d;break;
}
return sum+'0';
}
Status shownumbers(SqStack S)
{
int numbers = 1;
if(S.top == S.base)
{
printf("栈为空栈,无法打印\n");
exit(-1);
}
while(S.base < S.top)
{
S.top--;
printf("%c ",*S.top);
numbers++;
}
}
//驱动函数..................
int main()
{
int sum;
SqStack OPTR; //符号栈
SqStack OPND; //数字栈
InitStack(OPTR);
InitStack(OPND);
OperandType_EvaluateExpression(OPND,OPTR);
sum = GetTop(OPND) - '0';
printf("%d",sum);
return 0;
}
运行结果如下:
1*2+6/2*(2+3*5)#
53--------------------------------
Process exited after 16.61 seconds with return value 0
请按任意键继续. . .
存在BUG如下:
1,输入的整数必须小于10.
2,不能输入小数,除数必须大于被除数。
分析:
1.代码中由于通过getchar()读取,所以当输入10/5的时候,读取的其实是1 和 0 两个字符。
2.这个是因为int型的除法问题,比如当3/7的时候,并不是小数,而是得0。
对于的一个bug,我想到的是,可以在输入的时候,建立数组完成,但是这个会导致输入有限,或者继续用getchar()输入,输入后进行数字的判断来解决,想一想是可以实现的。如果是连续的数字,就累加,终止条件是下一个符号。
对于第二个bug,则是要建立float型的数据类型,把char型转换为float型,但是或许又潜在的问题?并没有尝试。
本文探讨了使用顺序栈实现算术表达式求值的过程,遵循先乘除后加减,先括号内的运算规则。算法中涉及两个栈,一个用于存放运算符,另一个用于存放运算数和结果。在实现过程中,遇到的bug包括字符输入问题和整数除法导致的精度丢失。针对这些问题,提出了改进方案,如通过数组处理连续数字输入和使用浮点数类型确保精度。
1411

被折叠的 条评论
为什么被折叠?



