表达式求值

Posted Amysear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了表达式求值相关的知识,希望对你有一定的参考价值。

 

表达式求值问题

①问题描述

表达式是数据运算的基本形式。人们的书写习惯是中缀式,如:11+22*(7-4)/3。中缀式的计算按运算符的优先级及括号优先的原则,相同级别从左到右进行计算。表达式还有后缀式(如:22 7 4 - * 3 / 11 +)和前缀式(如:+ 11 / * 22 – 7 4 3)。后缀表达式和前缀表达式中没有括号,给计算带来方便。如后缀式计算时按运算符出现的先后进行计算。本设计的主要任务是进行表达式形式的转换及不同形式的表达式计算。

②基本要求

l  从文件或键盘读入中缀表达式。

l  设计操作数为多位整数,操作符为加、减、乘、除、求模的中缀表达式求值算法。

l  设计将中缀表达式转换为后缀表达式的算法。

l  设计将中缀表达式转换为前缀表达式的算法。

l  设计后缀表达式求值算法。

l  设计前缀表达式求值算法。

l  输出各种形式的表达式。

③设计要点提示

l  算数表达式的计算往往是通过栈来实现的。

l  读入或扫描表达式的同时,完成运算符和操作数的识别处理。

l  识别操作数时,注意将其字符序列转换成整数(如:‘15’→15)或实数(如:‘15.4’ →15.4)形式进行存储。

l  可以将表达式转换成一棵二叉树,通过先序、中序、后序遍历得到前缀、中缀、后缀表达式。

l  仿表1来构建测试用例。

表1 表达式计算测试用例示例

测试项目

测试用例

预期结果

基本测试

3

3

1+2*3-4/2

5

11+22

33

1+22*(5-3)/4

12

(((2)))-3

-1

 

容错测试

1+2(

表达式出错提示

2/0

表达式出错提示

2%0

表达式出错提示

(2-4)Ù3.1

表达式出错提示

2+3)(-5

表达式出错提示

(((2))-3

表达式出错提示

2.5%2

表达式出错提示

1+++1

表达式出错提示

2 2

表达式出错提示

1#1

表达式出错提示

表达式出错提示

  1 #include <iostream>
  2 #include<string.h>
  3 #include<ctype.h>
  4 #include<malloc.h> /* malloc()等 */
  5 #include<limits.h> /* INT_MAX等 */
  6 #include<stdio.h> /* EOF(=^Z或F6),NULL */
  7 #include<stdlib.h> /* atoi() */
  8 #include<io.h> /* eof() */
  9 #include<math.h> /* floor(),ceil(),abs() */
 10 #include<process.h> /* exit() */
 11 /* 函数结果状态代码 */
 12 #define TRUE 1
 13 #define FALSE 0
 14 #define OK 1
 15 #define ERROR 0
 16 #define INFEASIBLE -1
 17 #define OVERFLOW 3
 18 /* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
 19 typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
 20 typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
 21 using namespace std;
 22 typedef char SElemType;
 23 #define STACK_INIT_SIZE 100 //存储空间初始分配量
 24 #define STACKINCREMENT 10//存储空间分配增量
 25 
 26 
 27 /*——————————————————————————栈的操作——————————————————————————*/
 28 typedef struct{
 29    SElemType * base;//在栈构造之前和销毁之后,base的值为NULL
 30    SElemType * top;//栈顶指针
 31    int stacksize;
 32 }SqStack;
 33 Status InitStack(SqStack &S)
 34 {//构造一个空栈
 35     S.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
 36     if(!S.base) exit(OVERFLOW);
 37     S.top=S.base;
 38     S.stacksize=STACK_INIT_SIZE;
 39     return OK;
 40 }
 41 Status DestroyStack(SqStack &S)
 42 {//销毁栈
 43     free(S.base);
 44     S.top=NULL;
 45     S.base=NULL;
 46     S.stacksize=0;
 47     return OK;
 48 }
 49 
 50 Status StackEmpty(SqStack S)
 51 {
 52     if(S.top==S.base) return TRUE;
 53     else return FALSE;
 54 }
 55 int StackLength(SqStack S)
 56 {
 57     return S.top-S.base;
 58 }
 59 Status GetTop(SqStack S,SElemType &e)
 60 {
 61     if(S.top>S.base)
 62         {e=*(S.top-1);return OK;}
 63     else return ERROR;
 64 }
 65 Status Push(SqStack &S,SElemType e)
 66 {
 67     if(S.top-S.base==S.stacksize)//若栈满,追加存储空间
 68     {
 69         S.base=(SElemType *) realloc (S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));
 70         if(!S.base) exit(OVERFLOW);//存储内存分配失败
 71         S.top=S.base+S.stacksize;
 72         S.stacksize += STACKINCREMENT;
 73     }
 74     *(S.top)=e;//可直接使用 *S.top++=e;
 75     S.top++;
 76     return OK;
 77 }
 78 
 79 Status Pop(SqStack &S,SElemType &e)
 80 {
 81     if(S.top==S.base)
 82     {
 83         cout<<"表达式错误,溢出!!"<<endl;
 84         exit(OVERFLOW);
 85     }
 86     e=*--S.top;
 87     return OK;
 88 }
 89 Status StackTraverse(SqStack S, void(* visit)(SElemType))
 90 {
 91     while(S.top>S.base)
 92         visit(*S.base++);
 93     printf("\\n");
 94     return OK;
 95 }
 96 
 97 
 98 //表达式求值
 99 char Precede(SElemType c1,SElemType c2)//判断c1,c2的优先关系,栈顶元素是c1,如果要入栈的元素c2优先权小(>),
100                                        //则弹出c1进行运算,再把c2继续尝试入栈,c1栈底,c2入栈运算符
101 {
102     char f;
103     switch(c2)
104     {
105         case \'.\' : f=\'<\';
106                    break;
107         case \'+\' :
108         case \'-\' : if(c1==\'(\'||c1==\'\\n\') f=\'<\';
109                    else f=\'>\';
110                    break;
111 
112         case \'*\' :
113         case \'/\' : if(c1==\'*\'||c1==\'/\'||c1==\')\') f=\'>\';
114                    else f=\'<\';
115                    break;
116         case \'(\' : if(c1==\')\')
117                     {
118                         printf("括号输入不合法!");
119                         exit(ERROR);
120                     }
121                    else f=\'<\';
122                    break;
123         case \')\' : switch(c1)
124                     {
125                     case \'\\n\':
126                               printf("缺乏左括号!");
127                               exit(ERROR);
128                     case \'(\': f=\'=\';
129                               break;
130                     default : f=\'>\';
131                     }
132                     break;
133         case \'\\n\' : switch(c1)
134                    {
135                      case \'\\n\': f=\'=\';
136                                 break;
137                     case \'(\':
138                         printf("缺少右括号!");
139                         exit(ERROR);
140                     default : f=\'>\';
141                    }
142     }
143     return f;
144 }
145 Status In(SElemType c)
146 { // 判断c是否为7种运算符之一
147     switch(c)
148     {
149         case \'.\' :
150         case \'+\' :
151         case \'-\' :
152         case \'*\' :
153         case \'/\' :
154         case \'(\' :
155         case \')\' :
156         case \'\\n\' :return TRUE;
157         default  :return FALSE;
158     }
159 }
160 SElemType Operate(SElemType a,SElemType theta,SElemType b)
161 { // 做四则运算a theta b,返回运算结果
162     switch(theta)
163     {
164         case \'+\':return a+b;
165         case \'-\':return a-b;
166         case \'*\':return a*b;
167         case \'.\':return a;
168     }
169     if(b!=0)  return a/b;
170     else
171     {
172         cout<<"分母不能为0!"<<endl;
173         exit(OVERFLOW);
174     }
175 }
176 SElemType EvaluateExpression(SElemType M[100])
177 {//算术表达式求值的算符优先算法。设OPTR和OPND分别为运算符栈和运算数栈。
178  //OP为运算符集合
179     SqStack OPTR,OPND;
180     SElemType a,b,c,x;
181     int m=0,n=0;
182     InitStack(OPTR); Push(OPTR,\'\\n\');
183     InitStack(OPND);
184 
185     GetTop(OPTR,x);
186 
187     int i=1;
188 
189     while(M[i]!=\'\\n\' || x!=\'\\n\')//当运算符栈栈顶元素为‘\\n’,并且此时\'\\n\'尝试入栈时,作为表达式结束的标志
190     {
191 
192         if(M[i]>=\'0\'&&M[i]<=\'9\') // M[i]是操作数
193         {
194             while(M[i]>=\'0\'&&M[i]<=\'9\')
195             {m=m*10+(M[i]-\'0\');i++;}
196             Push(OPND,m); // 将该操作数的值(不是ASCII码)压入运算数栈OPND
197             m=0;
198 
199         }
200         else if(In(M[i]))   // M[i]是运算符
201          switch(Precede(x,M[i]))
202         {
203           case \'<\': //栈顶优先权低,进栈
204             Push(OPTR,M[i]);i++;
205             break;
206           case \'=\': //脱括号并接受下一字符
207             Pop(OPTR,x);i++;
208             break;
209           case \'>\': //退栈并将运算结果入栈,不再getchar,将当前字符继续尝试压栈
210             Pop(OPTR,x);
211             Pop(OPND,a);
212             Pop(OPND,b);
213             Push(OPND,Operate(b,x,a));
214             break;
215         }
216 
217       else // c是非法字符
218       {
219         printf("出现非法字符\\n");
220         exit(ERROR);
221       }
222 
223       GetTop(OPTR,x); // 将运算符栈OPTR的栈顶元素赋给x
224     }
225     Pop(OPND,x);
226 
227     if(!StackEmpty(OPND)) // 运算数栈OPND不空(运算符栈OPTR仅剩′\\n′ )
228         {
229             printf("表达式不正确\\n");
230             exit(ERROR);
231         }
232 
233     return x;
234 }
235 
236 Status InToPost(SElemType M[100])
237 {
238     SqStack OPTR,OPND;
239     SElemType a,b,c,x;
240     int m=0,n=0;
241     InitStack(OPTR); Push(OPTR,\'\\n\');
242     InitStack(OPND);
243     GetTop(OPTR,x);
244     int i=1;
245     while(M[i]!=\'\\n\' || x!=\'\\n\')//当运算符栈栈顶元素为‘\\n’,并且此时\'\\n\'尝试入栈时,作为表达式结束的标志
246     {
247 
248         if(M[i]>=\'0\'&&M[i]<=\'9\') // M[i]是操作数
249         {
250             while(M[i]>=\'0\'&&M[i]<=\'9\')
251             {m=m*10+(M[i]-\'0\');i++;}
252             Push(OPND,m); // 将该操作数的值(不是ASCII码)压入运算数栈OPND
253             cout<<m;
254             m=0;
255 
256         }
257         else if(In(M[i]))   // M[i]是运算符
258          switch(Precede(x,M[i]))
259         {
260           case \'<\': //栈顶优先权低,进栈
261             Push(OPTR,M[i]);i++;
262             break;
263           case \'=\': //脱括号并接受下一字符
264             Pop(OPTR,x);i++;
265             break;
266           case \'>\': //退栈并将运算结果入栈,不再getchar,将当前字符继续尝试压栈
267             Pop(OPTR,x);cout<<x;
268             Pop(OPND,a);
269             Pop(OPND,b);
270             Push(OPND,Operate(b,x,a));
271             break;
272         }
273 
274       else // c是非法字符
275       {
276         printf("出现非法字符\\n");
277         exit(ERROR);
278       }
279 
280       GetTop(OPTR,x); // 将运算符栈OPTR的栈顶元素赋给x
281     }
282     Pop(OPND,x);
283 
284     if(!StackEmpty(OPND)) // 运算数栈OPND不空(运算符栈OPTR仅剩′\\n′ )
285         {
286             printf("表达式不正确\\n");
287             exit(ERROR);
288         }
289 
290     return OK;
291 }
292 int ArrayLength(SElemType M[100])
293 {//求数组的长度,不包含\'\\n\'
294     int以上是关于表达式求值的主要内容,如果未能解决你的问题,请参考以下文章

Java Eclipse 求值表达式

python 短路求值或惰性求值

Java 表达式中子表达式的求值顺序

表达式求值

中缀表达式求值的思路分析与代码实现

中缀表达式求值的思路分析与代码实现