表达式求值(顺序栈实现)

来源:互联网 发布:c语言中a=3是什么意思 编辑:程序博客网 时间:2024/06/04 20:00

问题:算数运算的表达式求知


这道题不难,但是当你认真去编代码的时候,还是要考虑好多细节。


算法原理如下:

我们都知道算术四则运算的运算规则是:

先乘除,后加减。

从左到右计算

先算括号内,再算括号外


表达式组成

任何一个表达式都有操作数、运算符和界定符组成。

操作数即可以是常量,也可以是被说明为变量或常量的标识符。

运算符可以分为算术运算,关系运算和逻辑运算符。

界定符有左右括号和结束符等。

本文为了方便演示只使用算术运算。


运算符优先级

对于连个相继出现的操作符θ1和θ有三种关系:大于、等于和小于。由此可以列出“+-*/”之间的优先级。如下表:


+-*/()#+>><<<>>->><<<>>*>>>><>>/>>>><>>(<<<<<=
)>>>>
>>#<<<<<
=

 

加减乘除优先性都低于“(”但是高于“)”,由运算从左到右可知,当θ12 ,令θ12

为了算法简洁,在表达式的左边和右边虚设一个“#”,这一对“#”表示一个表达式求值完成。


“(”=“)”当一对括号相遇时表示括号内已运算完成。

“)”和“(”、“#”和“(”、“(”和“#”无法相继出现如果出现则表达式出现语法错误。


为实现优先算法,可以使用两个工作栈,一个是OPTR,用于寄存运算符,一个是OPND,用于寄存运算数和运算结果。

代码如下:(存在一个bug)

#include<stdio.h>   //表达式求值,顺序栈 #include<stdlib.h>#define STACK_INIT_SIZE 100#define STACKINCREMENT 10#define OK 1#define ERROR 0typedef 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);elsee = *(S.top-1);return e;}Status Pop(SqStack &S, char &e){if(S.base == S.top)return ERROR;elsee = *--S.top;return OK;  }  Status IsDigit(char c){if(c >= '0' && c <= '9')return 1;elsereturn 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型,但是或许又潜在的问题?并没有尝试。

0 0
原创粉丝点击